• 要素が1つしかない連想配列のネストを解消する

    WordPress関数(特に$wpdbクラスなどに多い。get_results()メソッドでDBの値をとって来たときなど)を使っていて、戻り値の配列が一つしか要素持ってないのに連想配列になっていたりする場合、値を取り出すときにネストしたループ処理を書くケースが結構ある。 以前からコード的に冗長で非効率だよなぁ…と思っていて、今回改善方法を見出してスッキリしたので、ここにTIPSとして残しておこうかと。

    $array = array(
        array(
            'key_1' => 'value_1', 
            'key_2' => 'value_2', 
        ), 
    );
    
    foreach ($array as $nested_array) {
        foreach ($nested_array as $key => $value) {
            echo 'array["' . $key . '"] => "' . $value . '"<br />';
        }
    }
    

    今まではこんな感じに(無駄ではないのだが、効率的ではない)foreachループを連想配列の入れ子分回して値取ってた…。 で、この連想配列とループのネストを解消してシンプルに処理を書けないものか…とPHPのarray関数を色々と試してみた。array_reduce()とかarray_walk()とかあんまり使わない関数で、独自にネスト解消用の関数組んでもできるんだが、別途独自関数用意しなきゃならなくてまるでスマートでない…。なんかスパっと1ラインで解決できないかと試行錯誤してみたところ、ありました! array_shift()で先頭要素取得して元の配列変数を上書きしてしまえばいいのです。

    $array = array_shift($array);
    

    たったこれだけ(笑) でも、これだけだと配列の要素数が1つ以上でも上書きしてしまうので、要素数の判定を入れておく。

    $array = (count($array) == 1) ? array_shift($array) : $array;
    

    最初のコードをこのコード使って書き直してみると、

    ...
  • PATH_INFOを取得してhiddenに代入

    URLにパラメータをくっつけて、GETで送信する場合、

    http://www.example.com/?param0=aaa&param1=bbb
    

    という感じで渡して、受け取るときは

    $param0 = $_GET['param0'];
    $param1 = $_GET['param1'];
    

    または

    $param0 = $_REQUEST['param0'];
    $param1 = $_REQUEST['param1'];
    

    というようにするのが一般的ですが、以下のように、

    http://www.example.com/aaa/bbb/
    

    で値を渡して、受け取りは

    $param = split("[/\.]", $_SERVER["PATH_INFO"]);
    

    とすると、$param[0] に「aaa」が、$param[1] に「bbb」が代入されます。

    さて、これを WordPress でやろうとすると、「aaa」とか「bbb」をURLとして処理しようとしてしまい、当然パーマリンクや実体があるわけではないので、表示できません(実体があればそちらを表示しちゃう)。

    WordPress では PATH_INFO を使わない方がよさそうなのですが、使わざるを得ない場合、WordPress とは関係なく、一旦 PATH_INFO を受けるプログラムを作成し、そこから何かしらの方法で WordPress にパラメータを渡すようにします。

    受け方は上記の通りなので、あとは渡し方になるのですが、手軽なのは GET でリダイレクトする方法でしょう。

    $url = "遷移先URL?param0=" . $param0 . "&param1=" . $param1;
    header("HTTP/1.1 301 Moved Permanently");
    header("Location: " . $url );
    

    GETではURLにパラメータが見えるということであれば、セッションを使う方法もある。

    ...
  • 複数ファイルのアーカイブをダウンロードさせる時の方法

    例えば、複数個の画像ファイルをまとめてダウンロードさせたりする場合、サーバ上でテンポラリディレクトリに画像ファイルをコピーして、それらをアーカイブしてダウンロードさせたりします。 しかし、これだと画像ファイルをいちいちコピーすることになるので、ストレージを圧迫する可能性があるし、ファイル数が多いとコピーに時間がかかります。

    そこで、シンボリックリンクを作成し、そのディレクトリ毎アーカイブすることにします。

    まず、テンポラリディレクトリを作成します。

    $tmp_path = "/tmp/" . uniqid(rand());
    $archive_dir = "(指定したいディレクトリ名)";
    $tmp_dir = $tmp_path . "/" . $archive_dir;
    

    テンポラリディレクトリまでのパスと、テンポラリディレクトリ名を分けている理由は後述。

    次に、作成したテンポラリディレクトリに、画像ファイルのシンボリックリンクを作成します。

    // $filelists:画像ファイル名のリスト
    // $$image_dir:画像ファイルの格納ディレクトリ
    foreach( $filelists as $image_name ) :
        $target = $image_dir . "/" . $img_name;
        $link   = $tmp_dir . "/" . $img_name;
        symlink($target, $link);
    }
    

    あとは、このテンポラリディレクトリごとアーカイブします。特に画像ファイルの場合、圧縮してもサイズは余り変わらないので、tar でアーカイブすれば、圧縮処理が無い分、処理が早いです。 tarコマンドのオプションで「h」をつけることで、シンボリックリンクを実体としてアーカイブできます。これがキモですね。

    // アーカイブファイルパスを設定
    $tar_file = tempnam("/tmp", "DOWNLOAD");
    
    // tarコマンドでアーカイブ
    $command  = "tar chf $tar_file -C $tmp_path $archive_dir"; 
    system( $command );
    

    この時、tarコマンドのオプションで「-C」をつける。これで、指定したディレクトリに移動してから処理します。 こうすることで、テンポラリディレクトリのフルパスでアーカイブされずに済みます。

    ...
  • PHPに渡されたURLパラメータをそのままPHPの変数として使う

    PHPに何か値を受け渡して処理を行う時に、受け渡された値の存在チェックをしながらPHPの変数として定義し直すことは良くあります。でもそういうお決まりの処理を毎度書くのは何気に手間で、URLパラメータ名を変更するとまたその部分にも手を入れないといけなくなったりして面倒です。 そこで、どんなURLパラメータでもとりあえずそのパラメータ名を変数名として定義してしまえれば、変数定義の初期処理が楽になるし、モック版のPHP処理を書く時などはお手軽でかなり効率的かな…と思いました。

    と言うわけで、PHPの可変変数を使ってURLパラメータをそのままPHP変数化してみます。

    foreach($_REQUEST as $query => $value){
      ${$query} = (isset($value)) ? $value : '';
    }
    

    これで、どんなURLパラメータを受け取ってもそのパラメータ名を変数名としたPHP変数が定義されます。

    例えば、上記コードを含んでいる「test.php」に「test.php?a=test」でアクセスした場合、「test.php」ではURLパラメータの「a」が変数「$a」として定義されます。同じように「test.php?a=test&b=1&c=0」でアクセスすれば「$a」「$b」「$c」がそれぞれ定義されます。「$_REQUEST」のグローバル変数を可変変数に展開しているので、GETメソッドでもPOSTメソッドでも大丈夫です。

    なお、変数の定義状況は、

    print_r(get_defined_vars());
    

    で確認できます。

    でもこの方法で公開用のアプリを作ってしまうと、受け取った値を素のまま展開しちゃうので、クロスサイトスクリプティングや各種インジェクションのセキュリティホール化する可能性が高いので、あくまでモック開発とかまでの利用にとどめておいた方が良いです。

    ...
  • CANVAS版イメージトリマー

    任意の画像をHTML5のCANVASに読み込んで、範囲を指定してトリミングおよびリサイズし、ファイル形式を指定して出力するイメージトリマーツールです。
    処理の流れとしては、

    1. 指定されたディレクトリ内をサーチして画像ファイルだけをプルダウンメニューへ追加します。
    2. CANVASに読み込んだ画像の上にjQueryUIのドラッグ&ドロップボックス(divレイヤー)を重ねる。
    3. トリミングボタンが押されたらドラッグ&ドロップボックス(divレイヤー)のX,Y座標と縦横幅を取得します。
    4. 取得した座標と幅を元画像の実寸比に計算し直して、トリミング&最終出力サイズにリサイズします。
    5. 最終出力画像をCANVASのtoDataURL()メソッドでテキストデータ化して、AjaxでPHPへポストします。
    6. PHP側では受け取ったテキストデータをJPEG/PNGのバイナリデータへ変換して指定場所へ出力します。

    HTML5とJavaScriptだけではバイナリファイルをローカルへファイルとして出力することが出来ないので、PHP化で処理しました。

    画像ファイル管理ツールの拡張機能として開発しましたが、いまだ日の目を見ていないプロト版ツールです(なので、ツール自体の見た目ものっぺりしています)。

    利用コード:HTML5、JavaScript、jQuery、PHP

    イメージトリマー

    任意の画像をHTML5のCANVASに読み込んで、範囲を指定してトリミングおよびリサイズし、ファイル形式を指定して出力するイメージトリマーツールです。
    処理の流れとしては、

    1. 指定されたディレクトリ内をサーチして画像ファイルだけをプルダウンメニューへ追加します。
    2. CANVASに読み込んだ画像の上にjQueryUIのドラッグ&ドロップボックス(divレイヤー)を重ねる。
    3. トリミングボタンが押されたらドラッグ&ドロップボックス(divレイヤー)のX,Y座標と縦横幅を取得します。
    4. 取得した座標と幅を元画像の実寸比に計算し直して、トリミング&最終出力サイズにリサイズします。
    5. 最終出力画像をCANVASのtoDataURL()メソッドでテキストデータ化して、AjaxでPHPへポストします。
    6. PHP側では受け取ったテキストデータをJPEG/PNGのバイナリデータへ変換して指定場所へ出力します。

    HTML5とJavaScriptだけではバイナリファイルをローカルへファイルとして出力することが出来ないので、PHP化で処理しました。

    画像ファイル管理ツールの拡張機能として開発しましたが、いまだ日の目を見ていないプロト版ツールです(なので、ツール自体の見た目ものっぺりしています)。

    利用コード:HTML5、JavaScript、jQuery、PHP

    イメージトリマー

    ...
  • 画像ファイル管理ツール

    [caption id=“attachment_270” align=“aligncenter”]

    Image File Manageable Tools

    Image File Manageable Tools[/caption]

    あるECサイトのクライアント様より、「ECサイトに商品画像を登録する前に、ワークフローのルールに沿って撮影画像ファイルを一括でリネームしたい」というご要望をいただきまして、画像アップローダ付きのファイル管理ツールを開発しました。ECサイトで使われる商品画像の命名規則はそれぞれのECで微妙に異なっているので、最終的にはクライアント様専用ツールになってしまいましたが…。それでも、ファイルアップローダやリネーム処理といったコアの処理は汎用化しておけば転用や拡張が見込めるので、できうる限り汎用ツールとして開発しました。
    今回『DEVLAβ』で紹介しているツールはその汎用版のデモバージョンになります(ファイルのアップロードやファイル名変更といった機能はデモバージョンでは使えなくしているのでエラーになります)。
    コア機能はWordPress 3.3で採用されたドラッグ&ドロップ対応のファイルアップローダ「Plupload」を採用して、アップローダ以外のファイル管理部分のロジックを追加した形です。
    実装機能としては、下記のような特徴があります。

    • HTML5に対応しているブラウザではドラッグ&ドロップで画像ファイルのアップロードが可能(Pluploadの機能)。
    • 大きいファイルを分割アップロードできるChunk機能(Pluploadの機能)。
    • アップロード時に同時にリサイズも行えます(Pluploadの機能)。
    • ファイルアップロードの処理をログ出力(Pluploadの機能を拡張)。
    • アップロード画像を確認しながら個別もしくは一括でファイルのリネームが可能。
    • ファイル名から商品番号を類推して、自動でリネームパターンを想定してデフォルト値として設定することが可能。
    • 任意の画像を選択してグループ化でき、グループ化した画像ファイル群を別フォルダに抽出して出力できます。

    クライアントさんへの提供方式は「XAMPP + 本ツール」のセットをインストールパッケージ化して、納品させていただきました。
    クライアントさんからは拡張機能部分(「リサイズ」など)の要望がなかったため、その後ツールの拡張は行っていませんが、いつか汎用型ファイルマネージャとしてWordPressのプラグイン化みたいなものに進化させてみたいツールです。

    余談ですが、Eコマースでは、商品を採寸して、撮影して、紹介用の原稿を書くといった倉庫側の作業を「採寸・撮影・原稿」のそれぞれの頭文字を取って『さ・さ・げ』と呼びます。このツールはその作業の一番最後にECシステムに商品を登録する時に使われました。そのため社内では「ささげツール」と呼ばれていました。

    利用コード:HTML5、Plupload(JSライブラリ)、JavaScript、jQuery、PHP

    ささげツール

    ...
  • CSS3エディッター

    CSS3エディッター

    CSS3で追加されたプロパティは構文が長いうえに、ブラウザ毎に実装差異があるためベンダープレフィックスを付けて記述分けする必要などもあって、マークアップするのがなかなかに大変です。「Adobe Dreamweaver」などのCSS3に対応しているオーサリングツールを使えばだいぶマークアップが楽になりますが、ツールを持っていないクライアントの担当者さんやツールの知識がないマークアップエンジニアには対応できません。
    そこで、WEBベースで簡単に利用でき、視覚的で、設定が簡単なスタイルシート自動生成ツールを作ってみました。とあるスマートフォン専用のサービスにて、そのデザインテンプレートをWEB上から編集できるように…と開発したので、PC向けサイトやそのサービス以外のサイトに対応したオールラウンドのCSSエディッターにはなっていないのですが、CSS3でマークアップが面倒なグラデーションやボックスシャドウ、丸角などのコードを視覚的にエディットできて自動で吐き出してくれるので、CSSの特定プロパティの補助的な編集ツールとしては使えるかも知れません。
    (※CSS3の全てのプロパティには対応していません。CSS2.1以前のプロパティにもいくつか対応しています。)

    利用コード:HTML5、CSS3/CSS2.1、JavaScript、jQuery、PHP

    CSS3エディッター

    ...