タグ別アーカイブ: php

[PHP]エクセルで文字化けさせないCSVの作り方

タグ: , , , , | 投稿日: 投稿者:

おはこんばんにちは、いい年してモンハンしちゃってるモリです。

さて、今回はCMSの1機能としてよくあるCSVダウンロード機能に関する記事を書きたいと思います。
PHPで生成したCSVをエンドユーザーがダウンロードしてエクセルで開いたら文字化けしてる!って
事を無くす為のやり方です。

結論から言うとファイルの先頭にBOMを付与する事で文字化けを回避させることが出来ます。
エクセルにUnicodeと識別させるために付与します。
これがあるとエクセルは自動的に判別してくれます。
SIJISに変換する方法もありますが、UTF8のまま文字化け対応させるやり方です。

元データはこんな感じ
blog1

BOMなしのPHPソース

 
header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=sample.csv");
$fp = fopen('php://output','w');
$data = array(
		array('項目1','項目2','項目3','項目4'),
		array('データ1','データ2','データ3','データ4'),
		array('データ5','データ6','データ7','データ8'),
		array('データ9','データ10','データ11','データ12')
);
foreach($data as $output){
	fputcsv($fp, $output, ',','"');
}
fclose($fp);

これをエクセルで見てみると見事に文字化け
blog2

さっきのソースのデータ書き込み前にBOMを付与します。

 fwrite($fp, '\xEF\xBB\xBF'); 

BOMありバージョンで見てみるとちゃんと読み込めていますね。
blog4

おまけ:BOMありのPHPソース

header("Content-Type: application/octet-stream");
header("Content-Disposition: attachment; filename=sample.csv");
$fp = fopen('php://output','w');
fwrite($fp, "\xEF\xBB\xBF");
$data = array(
		array('項目1','項目2','項目3','項目4'),
		array('データ1','データ2','データ3','データ4'),
		array('データ5','データ6','データ7','データ8'),
		array('データ9','データ10','データ11','データ12')
);
foreach($data as $output){
	fputcsv($fp, $output, ',','"');
}
fclose($fp);

では。。。


[WordPress]需要度低めだけど意外と助かるカスタマイズ3選

タグ: , | 投稿日: 投稿者:

こんにちは、ニタです。
WordPressを利用したWebサイトを開発する際、既存テーマファイルをカスタマイズしたり、プラグインをインストールしていきます。
それでも対応できないものは、使用するテーマファイル内のfunctions.phpにコードを記述するなどして対応していきます。
今回は、その中でも需要度低めな?カスタマイズ方法をいくつかご紹介します。

generatorのmetaタグを削除

WordPressでは、headタグ内にgeneratorのmetaタグが挿入されます。
これはページ作成ツールの情報なのですが、あまり必要性がないのと、セキュリティ面を考慮しても削除したほうが良いです。
※バージョンを外部に晒すことになるので、WordPressをアップデートしていない場合、攻撃対象になるため。

利用中のテーマファイルにある、functions.phpに以下を追記すると、generatorのmetaタグが作成されません。

if(has_action('wp_head','wp_generator')) {
    remove_action( 'wp_head', 'wp_generator' );
}

これだけでもページのソース上からは削除されますが、同時に生成されるRSSフィードなどにも生成ツール情報が書き込まれるので、そちらも削除します。

$actions = array( 'rss2_head', 'commentsrss2_head', 'rss_head', 'rdf_header',
'atom_head', 'comments_atom_head', 'opml_head', 'app_head' );
    
foreach ( $actions as $action ) {
    if ( has_action( $action, 'the_generator' ) ) {
        remove_action( $action, 'the_generator' );
    }
}

WordPressからのメール送信でSMTPを利用する

WordPressには、wp_mailというphpmailerを使用したメール送信関数がデフォルトで備わっています。

関数リファレンス/wp mail – WordPress Codex 日本語版

サイトポリシー上、SMTPを利用してメール送信する場合は、phpmailerの設定処理をカスタマイズして対応します。
こちらも、functions.phpに記述します。
send_smtp_emailという関数名は適宜変更しても構いません。

add_action('phpmailer_init','send_smtp_email');
function send_smtp_email( $phpmailer )
{
    // SMTP有効設定
    $phpmailer->isSMTP();

    // メールサーバーのホスト名
    $phpmailer->Host = "使用するSMTPサーバ名";

    // SMTP認証の有無(true か false)
    $phpmailer->SMTPAuth = true;

    // SMTPポート番号(25,465,587など適宜) 
    $phpmailer->Port = "587";

    // SMTP認証時のユーザー名
    $phpmailer->Username = "ユーザー名";

    // ユーザーのパスワード
    $phpmailer->Password = "パスワード";

    // SMTP暗号化方式(tls か ssl)
    $phpmailer->SMTPSecure = "tls";

    // 送信者メールアドレス
    $phpmailer->From = "test@example.com";
    
    // 送信者名
    $phpmailer->FromName = "送信者名";
}

テーマ内でセッションを使う

基本的にWordPressのフロント側では、PHPのセッションは使用していません。
ページによってはセッションを利用したページ処理があると思います。
セッションを使う場合はこんな感じでfunctions.phpに記述します。
common_session_startという関数名は適宜変更しても構いません。

add_action('init', 'common_session_start');
function common_session_start(){
    if(!isset($_SESSION)){
        session_start();
    }
}

いかがでしたでしょうか。
ちょっとニッチなカスタマイズでしたが、ご利用いただければと思います。
それでは。


ajaxでクロスドメイン通信のやりかた

タグ: , | 投稿日: 投稿者:

こんにちは、kikuです。
今日はサーバー間で通信処理をjavascriptでしたいと思った時の実装例を記述していきます。

方法は色々あるかと思いますが、今回はajaxでやる方法について記述していきます。

ajaxでhoge.comにGETアクセスする処理例

クライアント側のコード例(hoge.comでないサーバーのコード)

    jQuery.ajax( {
        url: 'http://hoge.com',
        type: 'GET',
        success: function( data ) {
            console.log('通信に成功しました。');
        },
        error: function( data ) {
            console.log('通信に失敗しました。');
        }
    } );

サーバー側のコード例(hoge.comのコード)

header('Access-Control-Allow-Origin: *');
echo '成功です';

セキュリティの問題でサーバー側にも対応が必要なんです。
別のサーバーから無許可でアクセスが来て勝手にレスしていたら怖いですから当然ですね。

Access-Control-Allow-Origin:で許可するオリジンを決めます。

特定のオリジンのみ許可をする場合はこんな感じ

header('Access-Control-Allow-Origin: http://hoge.com');

クッキー情報を付けてアクセスしたい場合は

クライアント側のコード例(hoge.comでないサーバーのコード)

    jQuery.ajax( {
        url: 'http://hoge.com',
        type: 'GET',
        xhrFields: {
            withCredentials: true
        },
        success: function( data ) {
            console.log('通信に成功しました。');
        },
        error: function( data ) {
            console.log('通信に失敗しました。');
        }
    } );

サーバー側のコード例(hoge.comのコード)

header('Access-Control-Allow-Origin: ' . getenv('HTTP_ORIGIN'));
header('Access-Control-Allow-Credentials: true');
echo '成功です';

サーバー側にAccess-Control-Allow-Credentials: trueが必要になります。
更にAccess-Control-Allow-Origin:*が使えません。
ですが基本的にgetenv('HTTP_ORIGIN')で取得可能な場合が多いのでこれを付けておけば大体OKです。
※ダメだった場合は色々制限や工夫をすればいけますが省略します

今回はGETアクセスのみの紹介です。
POSTとかはまた色々やらなくてはいけませんので気をつけて下さい。。

 

参考
https://developer.mozilla.org/ja/docs/HTTP_access_control

 

 


WordPressプラグイン開発のポイント

タグ: , , | 投稿日: 投稿者:

こんにちは。ニタです。

前回、WordPressプラグインのリリース報告後、まともに開発する時間が取れなくて、プラグインの更新が出来ずにおります。
今回は、WordPressプラグインを開発する際の要点、ポイントをまとめてみます。

ディレクトリ、ファイル構成

プラグインは、WordPressのwp-content/plugins/内に格納されます。
プラグインファイルのみを格納するだけでも、WordPressは認識しますが、管理面も考慮して個別のディレクトリに格納しておくのが良いでしょう。
ディレクトリ名は、管理面も考慮して、プラグイン名と同じにするのが一般的です。
他のプラグインと重複しないよう予め調査するか、プレフィックスなどで唯一性を持たせるのもひとつの手です。
もし、開発したプラグインを、一般公開する場合、プラグイン名は特に考慮しておくべきでしょう。

rc_directory

また、プラグインのメインとなるファイル名(そのプラグインのメインとなる処理などが書かれたPHPファイル)は、プラグイン名にするのがWordPress界隈の慣例のようです。
ですが、ファイルの先頭に、プラグインの説明文をコメントアウトで記述していると、WordPressが勝手にメインとなるファイルとして判断するようです。

コメントアウトでプラグインの説明を記述

前述した、プラグインの説明文についてです。WordPressのプラグイン、テーマファイルは、コメントアウトでプラグインやテーマファイルの名称、バージョン、作者名、ライセンスなどを記述する必要があります。

/*
Plugin Name: (プラグインの名前)
Plugin URI: (プラグインの説明と更新を示すページの URI)
Description: (プラグインの短い説明)
Version: (プラグインのバージョン番号。例: 1.0)
Author: (プラグイン作者の名前)
Author URI: (プラグイン作者の URI)
License: (ライセンス名の「スラッグ」 例: GPL2)
*/

特に、プラグインに関しては、このような説明がないと、いくらpluginsディレクトリに格納しても、管理画面のプラグインページで表示されず、プラグインの有効化ができません。
最低でも、プラグイン名「Plugin Name」の項目だけは記述する必要があります。

フックについて。アクションとフィルタ

プラグインを開発すると言いましても、ざっくり言いますと「WordPressのコアファイル群で走っている処理の間に、自作の処理を挟ませて、処理結果を変える。その処理を作る」のが、WordPressプラグインの主な仕事です。
その自作の処理を挟ませることを、WordPressではフック(hook)と呼びます。

フックは、アクションとフィルタに分けられます。

アクションは、投稿を追加した時、テーマを切り替えた時などに走ります。

add_action('publish_post','hoge');

上記の場合、publish_postというアクションをフックに、hogeというfunctionを実行させています。
publish_postアクションは、投稿が公開された時のアクションですので、投稿が公開されたタイミングで、管理者にメールを送信する、ということも可能です。

フィルタは、WordPressのデータベースからデータをブラウザへ表示させる際、ブラウザからのデータをデータベースへ追加するタイミングなどに通る関数を指します。
僕が開発したプラグイン「Rucy」では、以下の様な使い方をしています。

add_filter('post_updated_messages','addRcMessage');

コアファイル群がpost_updated_messagesという、投稿内容を追加・更新した際に編集画面にメッセージを表示する関数に、addRcMessageという自作の関数を通しています。
addRcMessageでは、予約更新日時に関するメッセージを追加させています。
その結果、編集画面では、以下の様なメッセージが表示されるようになります。

rc_addmessage

アクションとフィルタの一覧はWordPress公式のWikiに掲載されていますので、参考にしてみてください。

アクションフック一覧
フィルターフック一覧

プラグインのインストール、アンインストール時のフック

プラグインを、管理画面で有効にした際、プラグイン独自の設定項目などをデータベースに登録したい場合があると思います。
その場合、以下のコードによってプラグインを有効にした際に、関数fugaが実行されます。

// fugaという独自関数を有効化時にフックさせる。
register_activation_hook( __FILE__, 'fuga' );

同様に、アンインストール、無効にした場合に実行させたい処理は以下のようにフックします。

// goodbyeRucyという独自関数をアンインストール時にフックさせる。
register_uninstall_hook(__FILE__, 'goodbyeRucy');

「Rucy」によってデータベースに追加された、予約更新内容や、設定内容を削除しています。
飛ぶ鳥跡を濁さずと言いますか、データベースなどに残したデータによって、アンインストール後のシステムに影響を与えないようにしています。

ざっと書きましたので、まとめますと、

  • プラグインはディレクトリ名、ファイル名は合わせる。
  • プラグイン名は唯一性を持たせる。
  • ファイルの先頭に、プラグインの説明文をコメントアウトで記述する。
  • プラグイン開発の基本はアクションとフィルターのフックを活用する。

こんな感じでしょうか。

このエントリーが、皆様のプラグイン開発の一助になれれば幸いです。
Enjoy, WordPressLife!


日付取得で気をつけておきたい事

タグ: , | 投稿日: 投稿者:

はじめまして、ニタです。

早速ですが、PHPで「今から数日後」「今から数ヶ月後」の日付が欲しい場合、こんな書き方をすると思います。

// 今から2日後
date('Y-m-d H:i:s',strtotime(date('Y-m-d H:i:s',time()) . "+2 days"));

では、以下の条件ではどうでしょうか。


$date = "2012-8-31 00:00:00";
$res = date('Y-m-d H:i:s', strtotime($date . " + 6 month"));
print_r($res);

結果は「2013-03-03 00:00:00」となります。
ですが、8月31日の6ヶ月後なので、2月末日(2013-02-29)でないといけないと思います。

これはstrtotime()において、以下の様に判断しているからのようです。
・2012年8月31日の6ヶ月後は2013年2月31日

・2月31日は存在しない

・31日は28日から3日後。つまり3月3日

最初の時点で日付の正当性をチェックをすべきなのですが、間違ってますね。
なので、ここは多少面倒ですが日付の正当性チェックを挟むようにします。


$sdate = "2012-8-31 00:00:00";
// 年月日時分秒毎に分ける
$hour = date('H',strtotime($sdate));
$min = date('i',strtotime($sdate));
$sec = date('s',strtotime($sdate));
$mon = date('m',strtotime($sdate));
$day = date('d',strtotime($sdate));
$year = date('Y',strtotime($sdate));
// 6ヶ月後の月の1日
$ym = mktime($hour,$min,$sec,$mon + 6,1,$year);
$arrayYm = getdate($ym);
// 日を置き換えて日時の正当性チェック
if(checkdate($arrayYm['mon'],(int)$day,$arrayYm['year'])){
    // そのままの日付で日時取得
    $res = mktime($arrayYm['hours'],$arrayYm['minutes'],$arrayYm['seconds'],$arrayYm['mon'], $day, $arrayYm['year']);
}else{
    // 6ヶ月後の末日にして日時取得
    $res = mktime($arrayYm['hours'],$arrayYm['minutes'],$arrayYm['seconds'],$arrayYm['mon'], date('t', $ym),$arrayYm['year']);
}
print_r(date('Y-m-d H:i:s',$res));

こんな感じで日付の正当性チェックをしつつ日付取得を行うと、いいと思います。