【PHP】無名関数で再帰呼び出しの落とし穴

こんにちは。 システム部のたかくです。業務でPHPに触りだしてから2ヶ月ほどになります。 デバッガがないのでステップ実行もない、変数の内容を拾うのにいちいち出力するの煩わしいなどと、 まだまだ開発環境そのものを見直したくて仕方ない時期です。

概要

さて、記事タイトルのお話になります。 “WordPressで、特定のスラッグを持つ最上位の固定ページから、最下位までの固定ページをリスト化する”という処理が必要になりました。 「wp_list_pages()があるじゃないか!」とも思いますが、ただリストが欲しいだけではありません。 適切な形でhtml出力するにあたって細かく制御する必要がありました。 ツリー型の構造を得たいなら再帰の出番です。 諸事情で新しく関数を書き足すことは避けたい状況でしたので、手続き的に書きたいなと思いました。 そうなると無名関数しかないよなーと思い、安易に手を出したら軽くハマってしまったのでその備忘録になります。 (PHPの無名関数は5.3からサポートされているようですよ)

最初に書いたもの

$family = function ($children) use (&$contents) {
    if (count($children) == 0) {
        return;
    } else {
        foreach ($children as $child) {
            // 前処理
            $nextChildren = get_children(array(
                'post_parent' => $child->ID,
                'post_type' => 'page',
            ));
            $family($nextChildren);
            // 後処理
        }
    }
};

$family($firstChildren);

(見づらいですが) 出力したいhtmlテキストの形式が若干特殊なため、最初に該当ページの最上位ページを拾ってからその直下のページだけを$firstChildrenとして取得しています。 それを無名関数に投げて再帰的に呼び出し、前処理と後処理の中で$contentsにhtmlテキストを格納していく、というものです。 変数のキャプチャの仕様はいろんな言語で違うため、真っ先に調べてuseを使うんだなーとぼんやり理解しました。 無名関数も関数の1つであるからか変数のスコープが外側と異なるため、$contentsには参照を渡さなければ処理が値に反映されません。 しかし、これで動いてくれることを期待しましたが見事に実行を停止してしまいます。

なぜなのか

無名関数の中と外ではまったく別のスコープであると予想します。 $familyという変数に無名関数を渡して、その中で$family()を再帰的に呼び出しています。 この無名関数は$familyという変数があることをまったく知りません。 スコープの外の存在は$contentsのように丁寧に教えてやらなければ見つけてくれないのです。 これが原因でした。

せいかい

$family = function ($children) use (&$family, &$contents) {
    if (count($children) == 0) {
        return;
    } else {
        foreach ($children as $child) {
            // 前処理
            $nextChildren = get_children(array(
                'post_parent' => $child->ID,
                'post_type' => 'page',
            ));
            $family($nextChildren);
            // 後処理
        }
    }
};

$family($firstChildren);

ちゃんと無名関数を渡す変数もuseでキャプチャしてあげましょう。 無名関数の中で自分を表すキーワード(クラスで言うthis)なんかが書ければ、 無名関数を渡される変数名が関数の定義の中の変数名に縛られないので、自由度が増すのですが… ありませんか?

[PHP]タイトルや本文に文字数制限して表示する場合に、出来るだけ終了地点を揃える。

タイトルのセンスがなさすぎて辛い…。

うまく伝える魅力的なタイトルが思い浮かびませんでした、システム部のヒライです。
端的に言いますと、WordPress等の記事一覧ページで、タイトルやら本文を省略して表示する場合に、それぞれの終点を揃えたいということです。

mb_substr()を使う。

文字数制限なんかで探しますとmb_substr()という関数が引っかかります。

75文字で省略し、最後に「…」を付けてみます。

mb_substr

 

・・・美しくない。

 

終わりに表示している「…」の位置がずれていてキレイじゃありません。

そんなときはmb_strimwidth()を使います。

こちらも同じく75文字で省略し、最後に「…」を付けてみます。

mb_strimwidth

 

・・・美しい。

 

終わりの「…」の位置が揃っています。大変キレイです。

mb_substr()とmb_strimwidth()の違い。

mb_substr()は全角文字列と半角文字列を判別せず、1文字としてカウントするのに対し、
mb_strimwidth()は全角なら2文字、半角なら1文字としてカウントしてくれるので、終了地点があまりズレないということですね、とても優秀です。

冒頭の話に戻り、例えばWordPress上でタイトルを省略しつつ、且つ終点を揃える場合。

[php]// 第一引数にタイトル、第二に始点(0文字目から)、第三に終点(100バイト分の文字)、第四に終点に付け加える文字列、第五に文字コード
<?php echo mb_strimwidth($post->post_title, 0, 100, "…", "UTF-8"); ?>[/php]

※mb_strimwidthについて詳しく知りたい方はこちらをご覧下さい。

一覧画面上に複数出ているタイトルや本文の終わりを揃えたいとお考えの方、ぜひお試し頂ければと思います。

WordPress管理画面 カスタム投稿の記事一覧画面で絞り込み検索を追加する

システム部の鈴木です。

先日、WordPressでファイルアップロードの機能におけるセキュリティホールの対策を行った最新版
4.5.2 がリリースされました。

弊社では沢山のサイトを管理させていただいておりますが、WordPressを導入しているサイトも多く
今回のような緊急性の高いセキュリティアップデートのときは一苦労です。

そんなWordPressについての小ネタです。

 カスタム投稿(Custom Post Type)

ブログというよりもCMSとしてWPを使う場合は、通常の投稿メニューでは無く
用途ごとにメニューを設けてそれぞれに適した入力項目を持った管理画面を作ったり、という事がよくあります。

そういった独自のメニューを作るときには「カスタム投稿(Custom Post Type)」という機能を使います。

 カスタム分類(Custom Taxonomy)

通常の投稿メニューとは別にカスタム投稿でメニューを作成したら、
その中でもカテゴリを設けたくなる場合があります。

それを実現するのが「カスタム分類(Custom Taxnomy)」というものです。

 

これらは Custom Post Type UI などのプラグインを使えばどちらも簡単に管理画面からの設定だけで作ることができます。

 

以上を踏まえて今回の本題です。

投稿一覧の画面には以下のようなカテゴリで絞り込むメニューがあると思います

20160527

カスタム投稿の一覧ページだと、カスタム分類を設定しても出てこないんですよね。
でも、検索があれば非常に便利。

ということで調べたところ、以下のようなコードが散見されました。

 

[php]
function add_post_taxonomy_restrict_filter()
{
global $post_type;
if (‘music’ == $post_type) {
$menu = <<<EOH
<select name="genre">
<option value="">カテゴリー指定なし</option>
EOH;
$terms = get_terms(‘genre’);
foreach ($terms as $term) { ?>
$menu .= ‘<option value="’ . $term->slug . ‘">’ . $term->name . ‘</option>’;
}
$menu .= ‘</select>’;

echo $menu;
}
}
add_action(‘restrict_manage_posts’, ‘add_post_taxonomy_restrict_filter’);
[/php]

これを使用しているテーマの function.php に書きましょう、というもの。
この例だと “music” というカスタム投稿で “genre” というカスタムタクソノミーから絞り込みを行う、というものです。
<select>のname属性には絞り込みに使うカスタムタクソノミーを指定するとの事です。

 

しかしこれ、どうもWordPressの4.4.1くらいからはうまく動かないみたいです。
メニューは出てきますがどうも上手く絞り込みがされません。

そこで訂正したものがこちらです。

[php]
function add_post_taxonomy_restrict_filter()
{
global $post_type;
if (‘music’ == $post_type) {
echo ‘<input type="hidden" name="taxonomy" value="music">’;
echo ‘<select name="term">’;
echo ‘ <option value="">カテゴリー指定なし</option>’;

$terms = get_terms(‘music’);
foreach ($terms as $term) {
echo ‘<option value="’ . $term->slug . ‘">’ . $term->name . ‘</option>’;
}
echo ‘</select>’;
}
}
add_action(‘restrict_manage_posts’, ‘add_post_taxonomy_restrict_filter’);

[/php]

変更のポイントは主に2つ

  • カスタム分類名は hidden で渡す
  • <select>のname属性は 検索対象とするキー、つまり “term” を指定する

この修正で上手く行きました。

 

 カスタム投稿、カスタム分類は非常によく使う機能なので、今後は本体で是非サポートしてほしいですね。

それまではこの方法をお試しください。

Smartyを導入するメリット

システム部の松田です。

サイトのお問い合わせや応募の入力フォームの実装・テストを担当することが多いのですが、その際によく利用するPHPのテンプレートエンジン「Smarty」について、まだまだ断片的な知識の整理を兼ねて、今回紹介したいと思います。

投稿は、前後編と2度に分ける予定で、

  • 前篇:PHP実装の問題点、それを補うSmartyのメリットなど概要
  • 後編:Smartyの使い方、ハマりやすいポイントなどの具体的な内容

のような構成でお伝えしたいと思います。

Continue reading

さくらインターネット環境のPHPからSSH2でアクセスするには

システム部の中村です。

遅くなりましたが、新年明けましておめでとうございます。

先日、実家で父がやっている内装屋の社員旅行があり、みんなでスカイツリーの久々に登ってきましたが、その時、赤坂方面見てみると、しっかり弊社が入っているアークヒルズフロントタワーが映ってました。

スカイツリーから六本木

いやー最近のカメラは性能上がる一方ですね

 

さてお得意様の案件で、

さくらのインターネットのライトプラン(レンタルプラン)で、PHPからSSHで他のサーバーに入り、各アカウントのディレクトリー容量等を定期的に調べないといけない案件の際、さくらインターネットでPHPからSSH接続する方法を記載します。

さくらインターネットさんのレンタルプランではPHPからSSH2関係のコマンドが使えないようになっています。

※ 要は phpinfoでSSHの項目が無い コンパイルされていないわけですね。

できないなら、php.iniで ssh2.so を 読み込めばいいじゃないか!

というわけで、

まずは、soファイル(共有ライブラリのファイル形式)を作ります。

tada,

SSH2のライブラリーをコンパイルするには、

libssh2 を準備しないといけません。

普通であれば、ソースをダウンロードして、”./configure  make make install”すればいいのですが、レンタルサーバー環境なのでもちろん /usr/sbinにアクセスできずコンパイル失敗となります。

なので、自分の領域にコンパイルします。

wget libssh2をダウンロード

tar で解凍

cd libssh2-1.4.3
./configure –prefix=/home/<USERNAME>/www/admin/libssh2/install
make
make install

これで、成功するはずです!

そのあと、同じ要領で、

wget ssh2をダウンロード

tar で解凍

cd ssh2-0.12

追記: phpize と打ち込みconfigure できるようにしてください。

./configure –prefix=/home/<USERNAME>/www/admin/libssh2/install/ –with-ssh2=/home/<USERNAME>/www/admin/libssh2/install/

make

make install  <=これは失敗します。コピー先がどうしても、/usr/sbin になるため

この段階で

ssh2.so が作られるので、

cp ssh2.so /home/<USERNAME>/www/admin/module/

のように適当な場所にコピーをして

PHPを動かす場所にphp.iniを設置し

error_reporting 8191
extension_dir=/home/<USERNAME>/www/admin/module/
extension = ssh2.so

としてやります。

すると、

phpinfo ssh

phpinfoで確認すると、SSHが動作することが確認できます。

soファイルで機能が使いできるので、いろいろ機能を増やしたり、することもこれで可能になるとは思います。

コンパイルできないレンタルサーバーでこれならかなり使い勝手がよくなるかな・・・

 

 

 

Really Simple CSV Importer を使って Advanced Custom Fields で作ったフィールドを登録する

システム部の鈴木です。
WordPressで多くの投稿を一気にインポートしたい場合、皆様はどうされてますでしょうか?

そんなときに便利なのが、CSVファイルから一気に投稿をインポートできる
Really Simple CSV Importer

ですが、今回は Advanced Custom Fields を使って作成した画像などのメディアアップロードのカスタムフィールドに登録したい場合にどうするか、ちょっと調べてみました
Continue reading

Codeignitor はじめました。のその後。

こんにちは。システム部の鈴木です。
先日、新年会で肥ったといじられました。暖かくなってから本気出します。

以前書いてからだいぶ間が空いてしまったCodeIgnitorを使って早速社内向けのサービスを作ってみました。
今回はそのときに気がついた点とか書いていこうと思います。

 

Continue reading

CodeIgnator はじめました。

システム部の鈴木です。

実は弊社にはひっそりとブログがあったりしたのですが、
この度めでたく弊社のfacebookページと連携する事になりました。
今後ともよろしくお願いいたします。

最近の弊社で担当させて頂く案件ではスクラッチでのある程度規模のある開発はそんなに多いわけでは無いのですが
※もっと開発やりたいので面白そうな開発案件お待ちしておりますw
現在、新たなサービスの開発に向けて日々開発を進めております。

これまでphpでの開発では個人的にはZend Framework またはZendをライブラリとして使って
おれおれフレームワークを作るみたいな感じの開発手法が多かったのですが
最近の弊社の開発ではCodeIgnitor を使うように変えることにしました。

ci_logo

Continue reading

ホットペッパーAPI

年末に都内へ集まってくる友人達との忘年会を開く関係で、先日ホットペッパーやいろんな飲食店のレビューサイト見ていたのですが、レビューサイト見てると、ホットペッパーの情報をブログパーツ的に表示しているサイトが数サイトあったので、

?APIでも提供してるのか?

と調べたところ、

リクルートWEBサービスなるものが、http://webservice.recruit.co.jp/hotpepper/

APIを提供してくれていました。

 

Continue reading

PHP開発でのMVCについて

行き帰りの電車の時間がわりと長いためよくGunosyで配信された記事を色々とみてるのですが
ちょっと前にPHP開発者のいうMVCについて物申す的な記事があり興味深く読んでました。

私もPHPでの開発はそこそこやってきていて、自分なりの考え方みたいなものもいっちょまえにもってたりするので
そんなものを今回は書いてみようかと思います。
 

Continue reading