• AWSのCloudwatchにアラート(Alarm)を設定し、監視する

    こんにちは。新人の橋本です。

    これまではオンプレミスのハイブリッドクラウド(プライベート+パブリック)や物理サーバにて運用構築業務についてましたが、

    AWS自体は初めて取り扱う環境ですので、その目線から、ブログを書いていきたいと思います。

    今回はAWS導入後、基本的なリソース監視ができるCloudwatchの設定、およびAlarmを設定し、閾値を超えたらEメールを送付するという

    ごくごく基本的な設定について記載します。

     

    1)設定画面

    EC2にてインスタンス作成後、EC2の[Instance]項目にてにてAlarm設定したいインスタンスを選択し、[monitoring]タブを選択します。

    スクリーンショット1

     

    2)Alarm設定

    右部分にある[Create Alarm]を選択すると、CreateAlarm画面が表示されるため、各項目を入力します。

    • Send a Notification to → 別項目にて、SNS topicを作成している場合、リストに追加されます(今回は追加しません)
    • Take the action → Alarm発生時のアクション。発生した場合どうするかを選択できます(今回は設定しません)
    • Whenever → リストより程度(Average,Max,Minimumなど)、および項目(CPU Utilization、Disk Usageなど)を選択します
    • Is → 閾値(○○パーセント以上or以下など)を設定します
    • For at least → 判定条件(○分間毎に△回[Whenever]項目が[Is]だった場合にAlarmカウントする)を設定します
    • Name of Alarm → Alarm名を設定します

    スクリーンショット2  

    3)設定追加

    各項目設定後、右下の[Create Alarm]を選択すると、Alarm項目が作成され、次の画面が表示されるので、リンクをクリックします。

    スクリーンショット3

     

    4)項目追加確認

    CloudWatch Management Console画面に遷移するため、項目が追加されたことを確認し、[Modify]タブをクリックします。

    ...
  • authorクエリを利用したWordPressのユーザー名漏洩を防ぐ方法

    DEVLABはWordPressで運用しているのだが、そのWordPressについて気になる記事を見つけた。 WordPressサイトのホームURLに「?author=x」のGETクエリをつけることで、サイト内のユーザー名がばれてしまう というものだ(※ 詳しくはMT SystemsさんのWordPress TIPを参照)。?author=xのxは数値で、WordPressのユーザーID(ユーザーテーブルのプライマリキー)となる。つまりxに1を指定すると、WordPressのルート管理ユーザーになるわけだ。 さっそく、DEVLABでも試してみたところ・・・ https://dev.blog.colorkrew.com?author=1がみごとにパーマリンク設定で指定されているリライトルールに沿ってリライトされ、https://blog.colorkrew.com/author/<ルート管理ユーザー名>/にリダイレクトされてしまった。このままだと、管理ユーザーのユーザー名に対してパスワードの総当りをされて、もしログイン成功とかされちゃうと、サイトがクラッキングされてしまうじゃないですか! ただ、DEVLABの場合、一般的なWordPressのログイン画面wp-login.phpは無効化してあって、ログイン方法を探すのが大変なので、一応は安全ではある。しかし、ユーザー名が漏洩してしまう脆弱性があるのは防止しないといけないので、対策を考えてみた次第。

    MT Systemsさんのサイトで紹介されているように、著作者アーカイブページのテンプレートauthor.phpによってリダイレクトしてしまう方法ではHTTPのレスポンスヘッダにリダイレクトのlocationとしてユーザー名が出力されてしまうため、たとえ.htaccessにrewriteルールを追加したとしても防止できないのが厄介だ。 MT Systemsさんのサイトでは、最終的にユーザーデータのuser_nicenameを書き換えて、ログインアカウントであるuser_loginと異なる値にしてしまう対処策が掲載されていたんだが、管理パネルから直接編集できない項目でもあって、なかなかに難儀である。

    もうちょっと簡単に対策できないものか…。 ──と、言うわけで、対策方法を自作してみた。

    // prevent the leakage of user name by author query on WordPress.
    function knockout_author_query() {
        // disable author rewrite rule
        global $wp_rewrite;
        $wp_rewrite->flush_rules();
        $wp_rewrite->author_base = '';
        $wp_rewrite->author_structure = '/';
        // for author query request
        if (isset($_REQUEST['author']) && !empty($_REQUEST['author'])) {
            $user_info = get_userdata(intval($_REQUEST['author']));
            if ($user_info && array_key_exists('administrator', $user_info->caps) && in_array('administrator', $user_info->roles)) {
                wp_redirect(home_url());
                exit;
            } else {
                // enable author rewrite rule
                $wp_rewrite->author_base = 'author';
                $wp_rewrite->author_structure = '/author/%author%/';
            }
        }
    }
    add_action('init', 'knockout_author_query');
    

    上記のソースをテーマのfunction.phpなどに追加することで即時有効になります。

    ...
  • WordPressのサイトが重くなった時のプラグインパフォーマンス検証

    とある多国語サイトをWordPressで構築している時に、結合試験もほぼ終わったあたりで、構築サイト全体のパフォーマンス・チューニングをしていた時の備忘録です。
    対象のサイトは規模がそんなに大きくなかったので、AWSのm3.mediumのインスタンスに構築していたのだが、開発途中からサイト全体のパフォーマンスが落ちて、だいぶ重いサイトになって来てました。サイトのパフォーマンス検証「GTmetrix」でのレポートを見ると、サイト内で利用している画像のレスポンスがレイテンシー食っているという結果しか出ず、とりあえずは出来る限りの画像最適化を行って、フロントエンドのパフォーマンスはだいぶ良くなったのだが、WordPressの管理画面は重いまま変わらなかった。WEBサーバ側で静的コンテンツのGZIP圧縮や、.htaccessを利用せずにhttpd.conf内に設定を移行など、諸々対応してみたが効果はなかった。他にMySQLTunerでDBの設定を検証・チューニングしてみたが、特に変化なし。
    う~む、CloudWatchを見るとCPU使用量がやけに大きいので、AWSインスタンスの非力さが原因なのかも…そうなると、最終的にはm3.mediumインスタンスからc3系へのインスタンス変更が必要かも知れないなぁ…とか考えていたのだが、そもそも開発中のサイトで社内の数人しかアクセスしない管理画面が重いというのは根本的に別の要因があるはず。サイト全体に関わるものというと、テーマかプラグインかしかない。そこで、導入しているプラグインのパフォーマンス検証を行ってみたところ、ビンゴ!…パフォーマンス低下の原因はプラグインだった。

    今回プラグインのパフォーマンス検証に利用したのが「P3(Plugin Performance Profiler)」だ。プラグインのパフォーマンスを検証するのに別のプラグインを入れるというのも変な話だが、このP3プラグインはWordPressサイト内でのプラグインやテーマのパフォーマンスを細かいところまでスキャン・レポーティングしてくれるかなり優秀なものだ。導入も簡単で、プラグインをダウンロードして有効化すればいつでも管理メニューの「ツール」からパフォーマンススキャンができる。

    このP3プラグインでスキャンした結果はこうなった。

    p3_before

    多言語化プラグインの「Polylang」とカスタム投稿タイプ系プラグインの「Types」がランタイムを圧迫しているのがわかる。さすがに多言語サイトなので「Polylang」は外せないが、カスタム投稿タイプ系のプラグインは同系プラグインが多いので差し替え可能だ。「Types」は「Polylang」に公式対応しているプラグインなので採用していたのだが、たかだかカスタム投稿の拡張をするだけで、ここまでランタイムを占有されてはちょっと使い勝手が良いとは言えない。
    そこで、「Types」プラグインを外して、同系で使い慣れている「Custom PostType UI」プラグインを導入してみた。

    p3_after

    「Types」で占有されていたランタイムがなくなり、プラグインロードタイムやプラグインインパクトが改善された。管理画面の体感速度も数十倍に向上し、本来のサクサク編集できるUXが復活した。プラグイン一つでここまでパフォーマンスが変わるものなんだなぁ…と実感できました。

    今回の件から、今後WordPressサイトを作る際には、プラグインの機能よりもパフォーマンスを重視して選定した方が良いと私的には思えました。なぜなら、プラグインの機能で足りないものは後からいくらでも追加することができるが、プラグインのコアに依存するパフォーマンスを改修するのは非常に困難だからです。
    特に管理画面が重いと、サイトを運用するWEB担当者のモチベーションがかなり下がってしまうので、ちょっと機能不足でもストレスなく運用できる管理画面の方が喜ばれるのではないだろうか。

    ...
  • WordPressサイトを簡単に他国語化できるプラグイン

    qTranslate プラグイン

    図1: qTranslate プラグイン

    WordPressはGNUのGettextを取り入れて多言語対応しているものの、実際に1つのサイトで多国語化を実現しようとすると、色々と困難な問題に突き当たる。とある開発案件にて多国語化の要望があったので、色々と言語系のプラグインなどを調べていたところ、見つけたのが「qTranslate」プラグインだ。

    このプラグイン、サイト全体の言語管理と各投稿毎(コンテンツ毎)の言語管理を一括で行えるという優れもののプラグインである。

    qTranslate プラグイン 2 図2: 管理パネルのメニュー

    管理パネルのメニューにてプラグインで指定した複数の言語を切り替えられるようになる(図2参照)のは序の口で、サイトのフロントエンド側からも言語を切り替えられる(切り替えのUIは別途作る必要はあるが…)。切り替え方も、ブラウザの言語設定に応じて自動化したり、訪問者の手動切り替えや、URLパラメータによる一時的な切り替えなど、色々と選べる。
    そして、極めつけが、それぞれ個別の投稿に対して別言語によるコンテンツを同時に投稿できる点が素晴らしい機能である。

    サイトの多国語化対応に際して一番大きな障壁が、サイトのメニューやフッター、ボタンといった共用コンテンツは言語ファイルにて他国語化できても投稿等のコンテンツはそれぞれ個別に管理しなければならないという点だ。例えば、日本語でアップした投稿と英語でアップした投稿はそれぞれ個別のコンテンツであり、それらを同じ一つのコンテンツとして管理するためには別の仕組みが必要だった。投稿のUI的にも同時に複数言語の記事が書けないことがネックとなって、サイトの保守性や利便性に難があったのだが、このプラグインはそれらの問題を一挙に解決してくれるのだ。

    ということで、モノは試しに、この記事を日本語と英語両方で投稿してみた。英語版を見てみる場合はこのリンクをクリックしてみて欲しい。

    qTranslate プラグイン 3

    図3: プラグイン設定画面

    「qTranslate」プラグインは2013年6月19日現在のバージョンが2.5.34であり、同梱されている日本語翻訳ファイルが古く、一部翻訳されない部分があったので、私の方で最新バージョンに合わせた翻訳を行ってみた。

    ※ 下記でダウンロードできた .mo ファイルを qTranslate プラグインの lang フォルダ内に入れてやる(上書きする)ことで最新の翻訳が反映されます。

    qTranslate プラグイン 日本語化ファイル

    動作確認:WordPress 3.5.1 / qTranslate 2.5.34

    ...
  • Contact Form 7 でエラー時用画面にリダイレクトする方法

    Contact Form 7では、管理画面の、各フォームごとの編集画面の「その他の設定」に、

    on_sent_ok: "window.location.href = 'リダイレクト先のURL';"
    

    と入力すれば、Contact Form 7 の処理終了後に、設定したURLにリダイレクトしてくれます。

    しかし、この設定をすると、成功しても失敗しても同じURLに遷移するため、送信が成功したか失敗したかわかりません。

    画面遷移ではなく、メッセージの表示をさせる場合では、成功時と失敗時でメッセージが切り替えられており、その処理にはJavaScriptを使っているはずです。

    そこで、Contact Form 7 のjsファイルを改変して、エラー時にエラー時用のリダイレクトURLへ遷移させることにします。

    /pm_webform/wp-content/plugins/contact-form-7/includes/js scripts.js

    67行目付近の以下の行

    } else {
    

    の下に以下の行を追加すると、失敗時用のリダイレクトURLへ遷移できます。

    window.location.href = "失敗時用リダイレクトURL";
    

    同様に、57行目付近の以下の行

    } else if (1 == data.mailSent) {
    

    の下に以下の行を追加すると、成功時用のリダイレクトURLへ遷移できます。

    window.location.href = "成功時用リダイレクトURL";
    
    ...
  • Contact Form DB でチェック処理

    Contact Form DB でテーブルへの insert を行う前に、何らかのチェック処理を入れたい場合、フックを使います。

    function my_form_chk( $cf7 ) {
    
                // 入力フォームの値取得
                foreach ($cf7->posted_data as $posted_name => $posted_value) {
                    // 元の値は変えないため別変数へ
                    $posted_name_2 = $posted_name;
                    $posted_value_2 = $posted_value;
    
                    // 値の整形
                    $posted_nameClean = stripslashes($posted_name_2);
    
                    $posted_value_2 = is_array($posted_value_2) ? implode($posted_value_2, ', ') : $posted_value_2;
                    $posted_valueClean = stripslashes($posted_value_2);
    
                    // それぞれの変数に代入
                    if( $posted_nameClean == 'a' ) {
                        $input_param_a = $posted_valueClean;
                    }
                    if( $posted_nameClean == 'b' ) {
                        $input_param_b = $posted_valueClean;
                    }
                    if( $posted_nameClean == 'c' ) {
                        $input_param_c = $posted_valueClean;
                    }
    
                }
    
                // チェック処理
                if ( $input_param_a !== $input_param_b || $input_param_a !== $input_param_c ) {
                      $cf7->skip_mail = true;
                }
    
    }
    
    add_action('wpcf7_before_send_mail', 'my_form_chk', 1);
    

    上記の例では、入力フォームで a,b,c という3つの入力項目があり、その値を受け取って、a と b、または a と c が一致指定なければ $cf7->skip_mail に true を代入しています。

    ...
  • Contact Form DB のテーブルについて

    Contact Form 7 というアンケートフォームのプラグインは、メールを送信するだけなので、DBへデータを格納するようにするプラグインが Contact Form DB です。

    両プラグインをWordPressに入れることで、手軽に入力フォームの内容をDBに格納できます。

    しかし、この Contact Form DB で作られるテーブルが曲者でした。

    WordPressの管理画面から Contact Form DB の管理画面を表示すると、入力フォームから入力されたデータの一覧を表示でき、それを見るとあたかも一つのフォームからの投稿が一つのレコードとして格納されているように見えます。 しかし、実際のテーブルには、入力フォームの input 一つ一つがそれぞれ1レコードとして登録されます。

    入力項目が3つのフォームだと、1回の投稿で3つレコードが登録されるわけで、それぞれのレコードには、それぞれの入力項目の内容のみが、投稿時間と入力フォーム名と入力項目名をキーに記録されるのです。

    ちなみにテーブル構造は下記の通り。

    mysql> DESC wp_cf7dbplugin_submits;
    +-------------+---------------+------+-----+---------+-------+
    | Field       | Type          | Null | Key | Default | Extra |
    +-------------+---------------+------+-----+---------+-------+
    | submit_time | decimal(16,4) | NO   | MUL | NULL    |       |
    | form_name   | varchar(127)  | YES  | MUL | NULL    |       |
    | field_name  | varchar(127)  | YES  | MUL | NULL    |       |
    | field_value | longtext      | YES  |     | NULL    |       |
    | field_order | int(11)       | YES  |     | NULL    |       |
    | file        | longblob      | YES  |     | NULL    |       |
    +-------------+---------------+------+-----+---------+-------+
    6 rows in set (0.03 sec)
    

    インデックス一覧は下記の通り。

    ...
  • iPhoneやiPadで撮影した画像を他のデバイスで見ると自動で回転してしまう場合の対処法

    .iphone { position: relative; height: 123.75px; width: 62.5px; border-radius: 8.75px; margin: 12.5px auto; background: -webkit-linear-gradient(-165deg, rgba(255,255,255,0.4), rgba(255,255,255,0.15) 35%, transparent 35%), -webkit-linear-gradient(top, transparent 21.25px, #222222 21.25px, #151515 102.5px, transparent 102.5px), -webkit-linear-gradient(top, #000, #0a0a0a); background-repeat: no-repeat; background-size: 100% 100%, 55px 100%, 100% 100%; background-position: 0 0, 3.75px 0, 0 0; box-shadow: 0 0 0 0.75px black, -10px -32px 0 -30.75px black, 0 0 0 1.25px #a09f9d, 12.25px -32.5px 0.75px -30.75px #777, 11.5px -32.5px 0.5px -30.75px #ddd, 15.5px -27.75px 0 -26.25px #8e8d8b, 15.5px -28px 0 -26.25px #b4b3b1, 15.5px -28.25px 0 -26.25px #666; } .iphone:after { content: ‘▢’; line-height: 11.5px; text-align: center; font-size: 7px; color: #666; position: absolute; width: 11.5px; height: 11.5px; border-radius: 50%; background: white; bottom: 4.5px; left: 25px; border: 0.5px solid #0a0a0a; background-image: -webkit-linear-gradient(left, rgba(0, 0, 0, 0.85), black); box-shadow: -9.75px -102.5px 0 -5.75px #000f31, -9.75px -102.5px 0 -5.5px #0a1c5a, -10px -102.5px 0 -5.25px #0d1216, -10px -102.5px 0 -4.75px #1b191a, -3px -102.5px 0 -5.5px #333, -2px -102.5px 0 -5.5px #333, -1px -102.5px 0 -5.5px #333, -0px -102.5px 0 -5.5px #333, 1px -102.5px 0 -5.5px #333, 2px -102.5px 0 -5.5px #333, 3px -102.5px 0 -5.5px #333, 4px -102.5px 0 -5.5px #333, 5px -102.5px 0 -5.5px #333, 6px -102.5px 0 -5.5px #333, -3px -102.5px 0 -4.5px #0a0a0a, -2.25px -102.5px 0 -4.5px #0a0a0a, -1.5px -102.5px 0 -4.5px #0a0a0a, -0.75px -102.5px 0 -4.5px #0a0a0a, 0px -102.5px 0 -4.5px #0a0a0a, 0.75px -102.5px 0 -4.5px #0a0a0a, 1.5px -102.5px 0 -4.5px #0a0a0a, 2.25px -102.5px 0 -4.5px #0a0a0a, 3px -102.5px 0 -4.5px #0a0a0a, 3.75px -102.5px 0 -4.5px #0a0a0a, 4.5px -102.5px 0 -4.5px #0a0a0a, 5.25px -102.5px 0 -4.5px #0a0a0a, 6px -102.5px 0 -4.5px #0a0a0a; } .iphone:before { position: absolute; content: ‘’; width: 0.5px; height: 29.25px; background: transparent; top: 10px; left: -1.75px; background-image: -webkit-linear-gradient(left, transparent 0px, transparent 0.25px, #7a7879 0.5px), -webkit-linear-gradient(top, #383838 0.25px, #b9b9b9 0.75px, #b9b9b9 2.5px, #383838 4.75px, #b9b9b9 5.75px, transparent 5.75px, transparent 13.25px, #383838 13.25px, #b9b9b9 13.5px, #dadada 14.5px, #383838 15.5px, black 15.5px, black 16.5px, #383838 16.5px, #b9b9b9 16.75px, #dadada 17px, #383838 17.5px, transparent 17.5px, transparent 25px, #383838 25px, #b9b9b9 25.25px, #dadada 26.25px, #383838 27.25px, black 27.25px, black 28.25px, #383838 28.25px, #b9b9b9 28.5px, #dadada 28.75px, #383838 29.25px); } .display { position: absolute; top: 21.75px; left: 2px; width: 56px; height: 80px; margin: 0; padding: auto; background: #fafafa; border: solid 1px #afafaf; font-size: 24px; font-weight: bold; line-height: 78px; text-align: center; vertical-align: middle; } .rotate_90deg { -moz-transform: rotateZ(90deg); -webkit-transform: rotateZ(90deg); -o-transform: rotateZ(90deg); } .rotate_180deg { -moz-transform: rotateZ(180deg); -webkit-transform: rotateZ(180deg); -o-transform: rotateZ(180deg); } .rotate_270deg { -moz-transform: rotateZ(270deg); -webkit-transform: rotateZ(270deg); -o-transform: rotateZ(270deg); } .device_deg_list { margin: 1em auto 2em; padding: 0; background: #ffffff; border: solid 1px #999999; } .device_deg_list th { padding: 2px; background: #d0d0d0; font-weight: bold; } .device_deg_list td { text-align: center; vertical-align: middle; } .device_deg_list td.odd { background: #f0f0f0; } .device_deg_list td.visual { width: 160px; text-align: center; vertical-align: middle; } .device_deg_list td.orientation { min-width: 120px; } .device_deg_list td.resampling { min-width: 200px; } .exif-value{ clear: both; display: block; font-size: 9px; color: #808080; }

    ...
  • wp_insert_attachment() で新規 insert

    wp_insert_attachment() のリファレンスには、

    wp_insert_attachment( $attachment, $filename, $parent_post_id );
    

    と書かれており、$parent_post_id を指定する必要があります。つまり、事前に posts テーブルに何らか insert して、そのレコードの post_id を指定することとなります。

    でも、新規で画像情報を登録したくて、でも紐づく投稿がまだ無い場合、post_id が無いわけで、どうするべきか調べてみました。

    WPのソースを追ってみて、実際に試してみたところ、

    wp_insert_attachment( $attachment, $filename, 0 );
    

    というように、$parent_post_id = 0 とすることで、新規で insert されます。

    ちなみに、$attachment には、

    $wp_filetype = wp_check_filetype(basename($filename), null );
    $wp_upload_dir = wp_upload_dir();
    $attachment = array(
         'guid'  => $wp_upload_dir['url'] . '/' . basename( $filename ), 
         'post_mime_type' => $wp_filetype['type'],
         'post_title' => preg_replace('/\.[^.]+$/', '', basename($filename)),
         'post_content' => '',
         'post_status' => 'inherit'
    );
    

    という感じで事前にアップロードしておいた画像の画像情報を入れてやればOK。

    ...
  • スクリプトで WordPress の DB にアクセスしたい

    WordPress の DB にスクリプトからアクセスしたい場合、単純に MySQL にアクセスして処理すればいいのですが、何らかの理由で WordPress の関数を使いたい場合(画像の投稿をスクリプトで行う等)は、

    require_once('wp-blog-header.php');
    

    でOKなのですが、一部のメソッドは直接そのメソッドが記述されたソースをインクルードする必要があります。

    例えば、カテゴリ登録するための wp_insert_category() を使いたい場合、

    require_once('/wp-admin/includes/taxonomy.php');
    

    とする必要があります。/wp-admin/includes/にクラスがあるので必要なものを探しだして、インクルードします。

    また、wp-blog-header.phpをインクルードするということは、例えば、HTTPSで必ずアクセスさせたり、ログインユーザのみに見せるといったようなWebの制限をfunction.phpなどに入れて、サイト全体に制限かけた場合、影響を受けます。

    そこで、そういった制限を入れた場合は、その制限処理に、

    if ( ! preg_match( '/^(script.php|hogehoge.*.php)/', basename( $_SERVER['SCRIPT_NAME'] ) ) ){
     // 制限処理
    }
    

    のように除外したいスクリプト名(上記の場合、「script.php」か「hogehoge.*.php」にマッチするスクリプト)を指定して、処理から除外する必要があります。

    これをしない場合、スクリプトを実行すると、制限に引っかかり、処理が止まります。

    ...
  • WordPressのデータベース仕様書を書いてみた

    以前から、 WordPressCodexのデータベース構造のページが見づらくて、仕様も古くなっていたのが、ちょっと気になっていたので、自分でデータベース仕様書を書き直してみようかと思っていたところ、WordPressでシステム開発する業務が急激に増えて来て、特にマルチサイト系の仕組みを把握する必要もあって、WordPressのデータベース仕様書をチートシート的に書き起こしておかないとシステム設計がしづらいという状況になってきた。そこで、自分なりのデータベース仕様書(テーブル定義書)を書いてみた次第。

    基本的には日本語版Codexと本家WordPress.orgのサイトを見ながら、実際のデータベース構造と見比べて書いてみたのだが、マルチサイト系のテーブル部分はまだちょっと不明なところが多いんだなこれが(特にwp_sitecategoriesテーブル…このテーブルってwp3.0以降ではドロップされてしまったのか?…みたいな)。

    まぁ、一通り書き切ったので、ここに共有化しておこうかと。

    バージョン:0.1

    さて話は変わる(…ようでそうでもないのだ)が、今月12/11に新安定バージョンのWordPress3.5がリリースされたので、さっそく本デベラボも3.5へアップグレードしてみた。
    管理パネルからの自動アップデートが上手く動作しなかった(パッケージデータを取得して展開している途中でタイムアウトしてしまう)ので、一旦アップグレードするのを躊躇したのだけど、PHP側の設定を見直すのは面倒だったので、最終的に手動でアップデートしてしまいました。アップデート後、今のところテーマやプラグインに不具合もなく動いているようだけど、管理パネルに常にWordPressの自動更新失敗のノーティフィケーションが出るようになってしまった…(大した影響はなさそうなので、そのうち直そうかと)。

    そんなわけで、WPも3.5になったので、書き上げたデータベース仕様書と構成の突合せをしてみようと、バージョン3.5のデータベースを覗いてみた。
    ざっと構造を見てみましたが、3.4.x → 3.5 でデータベースへの変更はなかった(マルチサイト側は突合せてませんが…)。

    本記事が今年最後のデベラボの投稿になりそうだ。
    それではみなさん、良いお年を。

    ...
  • 【WordPressを使う】WindowsPCで動かしてみる

    WordPressを仕事で扱うことになったので、試しにいつも使っているWindowsPCに入れてみることにしました。

    さてどうすれば動かせるのかと調べてみると、WordPressはPHPとMySQL、Apacheがあれば動くようで、WindowsPCではWebアプリを動かすのに必要なソフトウェアをひとまとめにした「XAMPP」というものをインストールして、それを利用してWordPressを実行できるようです。

    というわけで、まずはXAMPPをインストールすることに。

    ...
  • WordPressでHyperDBによるデータベース二重化を行う時の注意点

    商用サイトなどをWordPressで構築する場合、WEBアプリケーションサーバとデータベースサーバを切り離して、データベース側を二重化することが良くあります。単にデータベースへのアクセス負荷を分散させてサービスのパフォーマンスを向上させるためでもあり、もし障害が発生した場合にミラーリングしている副系ノードのデータベースから正系データベースを復旧させることができる意味でも、サービスとして最悪のケースである「データ消失」のリスクを軽減できるからです。
    WordPressにはそういう正副ノードのミラーリングデータベース構成にも対応できる「HyperDB」というドロップインがあります。これを使うことで、データベースの更新はマスターデータベースのみに集約し、データベース参照はマスターとセカンダリに分散させるということができます。
    (※ 「HyperDB」ドロップインによるデータベース二重化の方法は、QuickKnowLedge : MySQL HyperDB + Keepalivedを利用した、wordpress の負荷分散 などで詳しく説明されています。)

    さて、この「HyperDB」を利用しているWordPressサイトで、WordPressのコア処理に依存しない形で、データベースアクセスの処理を独自拡張している場合に、問題が発生することがあります。
    一体どういうケースかと言うと、WordPressのデータベース制御系のグローバル変数「$wpdb」をWordPressページ外で使う場合です。

    例えば、WordPressの投稿からAjaxなどで直接独自に作成したPHPをコールし、そのPHP内でWordPressのデータベースへのアクセスを行う処理があるような場合です。このようなWordPressのプログラム群から独立した外部プログラムでデータベースアクセス用のグローバル変数「$wpdb」を利用する場合に、
    [code lang=“php” light=“true”]require_once(’./wp-config.php’);[/code] …と、上記のように設定ファイルをインクルードしているケースだと「HyperDB」を有効化した途端に動かなくなります。

    この場合、インクルードするファイルを設定ファイルからブログヘッダーに変更することで、正常化します。
    [code lang=“php” light=“true”]require_once(’./wp-blog-header.php’);[/code]
    特にインクルードファイルを変更してもパフォーマンスに変化が見られなかったため、結論的には、外部プログラムで「$wpdb」を利用する場合は「wp-blog-header.php」をインクルードしておくのが無難なようです。

    ...
  • APCによるWordPressの管理画面にログインできない障害

    WordPressサイトを構築していて、インストール直後に通常アクセスはできるのに、ログインページからログインすると画面が真っ白になってログインできない症状に出くわしたので、その解決方法を備忘録として残しておこうかと。

    Codexに上記のケーススタディが載っていたのだが、該当する原因や解決方法がなかったので、エラーログを確認してみた。
    [code light=“true”] PHP Fatal error: Call to undefined function get_option() in /var/www/html/wp-admin/admin.php on line 32, referer: http://******/wp-login.php[/code] と、出ている。エラーでは管理画面の本体 admin.php にて get_option 関数が定義されていないと言っている。ちなみに、インストールしたWordPressのバージョンは3.4.1(2012年8月29日時点最新)である。

    今度はマニュアルサイトで関数を確認すると get_option() は wp-includes/functions.php で定義されているとのこと。そこで、wp-admin/admin.php のソースを追ってみると、30行目で wp-load.php が require_once されていた。wp-load.php では、48行目で load.php が require_once されており、その後で wp_load_translations_early() がコールされている。
    load.php の668行目で定義されている wp_load_translations_early の関数内で、該当の functions.php が require_once されているので、このインクルード処理前に return されてしまっている可能性があるのでは…と思い調査してみた。
    だが、いくら変数をvar_dumpしてみてもわからずじまい…うぅむ、困った。

    ...