return $this->getHelper('viewRenderer')->setNoController()->setScriptAction("controller/action");
2011年11月8日火曜日
Zend Framerowkでデフォルトと異なるビュースクリプトでレンダリングする
2011年10月11日火曜日
短縮リンク先取得であらためて、KISSの原則について考えた
いっぽう、Twitterクライアントを開発している人たちは、t.co/...の短縮リンクを展開するにはどうしたらいいか、必ず直面する課題だと思います。bit.lyにあるようなAPIは提供されていないのです。
bit.lyをいままで使っていた私は、APIがないから展開できないと考えていたのです。しかし、よくよく考えてみると実際にt.coのリンクにアクセスして、リダイレクトをたどっていけば最終的には求めるURLにたどり着けるはずです。
開発の現場でスケジュールに追われていると、このような発想の転換はなかなかできません。後になって冷静に考えると、問題を解決しようとしてかえって問題を複雑にとらえてしまっていることが多々あります。
詰まってしまったら、まず以下を意識すると解決の糸口になるかもしれません。
- 大きな問題は細かく分割する
- 難しくかんがえない。自分だけだとなかなか気づかないことも多いので、第三者のアドバイスをあおぐのも手です
(おまけ)短縮リンク取得(Zend Framework版)
$config = array( 'adapter' => 'Zend_Http_Client_Adapter_Curl', ); $client = new Zend_Http_Client(短縮リンクのURL, $config); $client->setMethod(Zend_Http_Client::GET); $response = $client->request(); if ($response->getStatus() == "200") { $url = $client->getUri(true); }
2011年9月18日日曜日
phpのエラーハンドリング
関数
- error_reporting
- 出力する PHP エラーの種類を設定する
ディレクティブ
- error_reporting
- error_reporting()関数同様の機能。ただし演算子の記述に制限あり
- display_errors
- エラーをHTML出力の一部として画面に出力するかどうかを定義する
- log_errors
- エラーメッセージを、サーバーのエラーログまたはerror_logに記録するかどうかを指定する
- error_log
- スクリプトエラーが記録されるファイル名を指定する
それぞれのおすすめ設定
error_reporting
E_NOTICEもログ出力しておくとバグに気づくことがあります。display_errors
開発環境ではtrue、本番環境ではfalse(これは必須)log_errors
開発環境、本番環境問わずtrueerror_log
省略するとapacheのエラーログに記録されます。アプリケーション個別のエラーログファイル名を決めて指定することを推奨。まとめ
- 本番環境、開発環境問わずerror_reportingにはE_NOTICEも記録する
- 本番環境ではdisplay_errorsは必ずfalseを指定。開発環境ではお好みですが、trueを設定しておくと画面に表示されるので対応漏れを減らすことができます。
- エラーログはアプリケーションごとにファイルを分ける。これにより、監視するときもアプリケーション単位で行うことができます。
注意
error_reportingに設定するE_ALLの値がphpのバージョンで変わります。 このせいでphpのバージョンアップをしたとたんに大量のエラーログに見舞われることがあります。これについてはまた別の機会に。2011年9月2日金曜日
phpでメモリ使用量に気を使う意味
PHP 5.2.0より後では"128M"、PHP 5.2.0 より前は "8M"、PHP 5.2.0 では "16M"となっており、php 5.2.0より前ではかなり少ない値となっています。 このメモリ制限のしくみは、便利でもあり、不便に思うこともあります。
リクエストを処理してレスポンスを返すウェブアプリケーションではメモリを大量に使用することはまれです。memory_limitののおかげでバグを仕込んでしまったループでメモリが消費されてエラーで気づいて助かったことがあります。
いっぽう、バッチ処理のようなスクリプトでは、内容にもよりますがメモリ使用量に気をつけていないと、途中で「PHP Fatal error: Allowed memory size of **** bytes exhausted」が発生して、中断してしまい悲惨です。
これを避けるために、memory_get_usage()でメモリ使用量を調査するデバッグコードを仕込んでおくのは良い習慣といえるでしょう。そして、もしPHP Fatal Error:...が発生してしまったら、まずロジックに問題がないか調べ、それからmemory_limitの値の変更を検討します。
そして、明示的にmemory_limitを指定しておけばphpのバージョンアップによる影響も避けられます(ini_setで設定できるのでスクリプトごとに変えられます)
2011年8月29日月曜日
phpの出力制御
header()の前には出力はできない(はず)
phpのマニュアルのheader()関数の説明に<html>とあります。たしかにおぼろげに
<?php
/* これはエラーとなります。この上に出力があることに注目してください。
* それはheader()のコールより前であるということになります */
header('Location: http://www.example.com/');
?>
Cannot modify header information - headers already sent by ...
こんなワーニングを見た記憶があります。
このワーニングを再現しようと思い上記のコードをテストサーバに配置しアクセスしてみたのですが、ワーニングも出ずにきちんとリダイレクトされてしまいました。なぜ!? 納得がいくまで調べていたら数日が経過してしまいました…
調査
サーバからのレスポンスをヘッダを含めて確認したかったので、いろいろ手段はありますが今回は Burp Suite を使いました。レスポンスはこのようになっていました。
HTTP/1.1 302 Found Date: Mon, 29 Aug 2011 **:**:** GMT Server: Apache/2.2.16 (Ubuntu) X-Powered-By: PHP/5.3.3-1ubuntu9.5 Location: http://www.example.com/ Vary: Accept-Encoding Content-Length: 7 Content-Type: text/html <html><html>を先に出力しているのに、きちんとheader()関数が有効で、Location:ヘッダが出力されていました。これは明らかに、
出力バッファリング
ですよね。でも、出力制御関数は一切使っていないのに…となると、答えはもう、php.iniしかありません。テストした環境(ubuntu server 10.10, php 5.3.3)のphp.iniを見てみると…
output_buffering = 4096見つけました。この設定があるおかげで、header()の前に出力があってもheader()が有効でした。ためしに、
<html> <?php echo str_repeat(" ", 4096); header('Location: http://www.example.com/'); ?>このように余計な文字列を出力し Content-Length: が4096以上になると、その時点でバッファに溜め込んだ出力がヘッダとともに出力されてしまうので、次の header("Location:"... でワーニングが発生し、リダイレクトもされません。
以上をふまえて注意
header()を使うときは- header()とコンテンツの出力の順序に気をつける。これはMVCの分離ができていれば容易にできるはずです。
- output_bufferingの設定を明示的に行う。php.ini以外に.htaccessやhttpd.confでも可能です。
2011年8月23日火曜日
phpでテキストファイルを読み込む方法あれこれ
まずは、読み込むファイルを用意しました。「なんちゃって個人情報」さんを使わせていただきました。
三上 恭子 藤岡 六郎 吉村 隼士 沢尻 由宇 朝倉 光博今回取り上げるのは
- file
- file_get_contents
- fopen - fgets
<?php // file() 1行1要素の配列に読み込む $list = file("sample.txt"); var_dump($list); // 全体をひとつの文字列に読み込む $s = file_get_contents("sample.txt"); var_dump($s); // 1行ずつ読み込む $fp = @fopen("sample.txt", "r"); while (($line = fgets($fp))) { $line = rtrim($line); echo $line . PHP_EOL; } @fclose($fp);巨大なファイルを file や file_get_contents で読み込もうとするとメモリ不足のエラーが発生する可能性がありますので、ケースによって1行ずつ読み込む昔ながらのfopen - fgets と使い分けるとよいでしょう。
さきほどのスクリプトの実行結果は以下になります。
array(5) { [0]=> string(14) "三上 恭子 " [1]=> string(14) "藤岡 六郎 " [2]=> string(14) "吉村 隼士 " [3]=> string(14) "沢尻 由宇 " [4]=> string(14) "朝倉 光博 " } string(70) "三上 恭子 藤岡 六郎 吉村 隼士 沢尻 由宇 朝倉 光博 " 三上 恭子 藤岡 六郎 吉村 隼士 沢尻 由宇 朝倉 光博
SyntaxHighlighter 再び
テンプレートが保存できない
前回同様、前に公式ページを参考にjavascriptを配置して、「テンプレートを保存」したところ、エラーが発生しました。テンプレートの形式が適切でないため、解析できませんでした。 すべての XML 要素が適切に閉じられているかどうかを確認してください。これは、しばらく考え込んだ結果、javascript中の不等号'<'を'<'に書き換えればよいことに気がつきました。アポストロフィは保存時に勝手に書き換えるのに、不等号はやってくれないのですね…
XML エラー メッセージ: The content of elements must consist of well-formed character data or markup.
動いているようで動かない
これでテンプレートの保存ができたので、期待を込めて「プレビュー」したのですが、シンタックスハイライティングが有効になりません。javascriptの文法に問題があるかもと、Chromeのデベロッパーツールで確かめてみたところ、スクリプト自体の動作は問題ないようです。途方にくれ、web上をいろいろ検索していたところ、window.onloadのイベントで初期化を行えばよいということが判明しました。公式サイトのExamplesを見てもそういう説明はないのですが、autoloaderを使うときは初期化タイミングに気をつける必要があるようです。(ソースコードを追う気になれず:-;)
ようやく動いたのが下のコードです。
これで読み込むjavascriptの数も減って、多少軽はくなったんでしょうか。ブラウザのキャッシュに一回入ってしまえば差がないのでは?という気がしないでもないです。
2011年8月21日日曜日
phpで必須パラメータの指定忘れをチェック
function fooBar($name, $age, $mail, $sex, $state) { ... }関数仕様が変更されたとき、呼び出し側のインパクトが大きいからです。phpはスクリプト言語のため、事前にコンパイルして引数の数が一致しているか検知することもできません。
この解決策として、パラメータをオブジェクトや連想配列で渡すように設計するのですが、今回は連想配列の一例です。
/** * パラメータチェックサンプル * * @param array 'name', 'age', 'sex', 'state'をキーにもつ連想配列 */ function fooBar($params) { $diff = checkEssentialParams($params, array('name', 'age', 'sex', 'state')); if (count($diff) > 0) { // $diffには不足しているパラメータ echo print_r($diff, true) . "パラメータが指定されていません。\n"; return false; } } function checkEssentialParams($params, $essential) { return array_diff($essential, array_keys($params)); } fooBar(array("age" => 30));checkEssentialParams関数の中で array_diff を使って連想配列中のキーのセット忘れをチェックしています。
実行結果
> php check_essential_params.php Array ( [0] => name [2] => sex [3] => state ) パラメータが指定されていません
2011年8月20日土曜日
phpのキャスト
foreach (array_merge(array_keys($this->_missingFields), array_keys($this->_invalidMessages)) as $rule) { foreach ((array) $this->_validatorRules[$rule][self::FIELDS] as $field) { unset($this->_data[$field]); } }
(array) $this->_validatorRules[$rule][self::FIELDS]arrayへのキャストですか? C,C++ではキャストといえばスカラー型どうしか、あってもポインタのキャストしか触ったことがないので違和感があります。ということで、調べてみました。
phpのマニュアルの「型の相互変換」のページには、キャストの一覧にこう書いてあります。
使用可能なキャストを以下に示します。(array), (object), (unset)あたりがクセモノですねぇ。(unset)なんて使い道すら想像できません。
- 整数へのキャスト
- (bool), (boolean) - 論理値へのキャスト
- (float), (double), (real) - float へのキャスト
- (string) - 文字列へのキャスト
- (array) - 配列へのキャスト
- (object) - オブジェクトへのキャスト
- (unset) - NULL へのキャスト (PHP 5)
arrayへのキャストは、マニュアルを読めばすぐ理解できました。
要素1つの配列に変換するというキャストでした。
これが何の使い道があるかというと、phpの関数の引数のアバウトさと関係しています。phpは関数の引数のチェックを厳密に行う必要がないため、スカラ型でも配列でも引数としてokという関数が作成できます。
そして、関数内部では(array)にキャストしてやれば、スカラ型が渡されたとしても配列として扱うことができます。
簡単な例です。
function echoList($list) { $list = (array)$list; foreach ($list as $element) { echo $element . PHP_EOL; } }キャストすることで、if (is_array($list)) ... と分岐する必要がなくなります。
2011年8月18日木曜日
javascriptで部分文字列を扱う
以下のコードは、文字列 s の一番最後の文字の一つ手前の文字を取りだすつもりで書いています。
funtcion substr_test() { var s = "0123456789"; alert(s.substr(-2, 1)); }
手元の"Google Chrome 13.0.782.112 m"や"FireFox 6.0"では期待通りの "8" が表示されるのですが、IEで期待通りの値を返してきません。
リファレンスをよく読むと、
注: start の引数に負の数の値を指定することは、Microsoft JScript [1] ではサポートされません【訳注: JScript で start に負の数を指定した場合、正の数として扱われます】 。とありました。
IE8, IE9で動作を確認してみたところ、「互換表示」が有効かどうかで結果が変わることがわかりました。
IE8(互換表示有効) | IE8(互換表示無効) | IE9(互換表示有効) | IE9(互換表示無効) | |
---|---|---|---|---|
動作 | × | ○ | × | ○ |
対策
startに負の数が指定された場合は、文字列長から逆算して正の数を指定してやれば解決です。ついでに、取り出す文字列長にも負の数を指定できるようにして、phpと同じ挙動にした substr_ex メソッドを作ってみました。String.prototype.substr_ex = function(start, length) { var l = this.length; if (start < 0) { start = l + start; } if (length < 0) { length = l - start + length; } return this.substr(start, length); }
2011年8月16日火曜日
シンタックスハイライティング
タイトルのとおり、シンタックスハイライティングです。
ブログの性質上プログラムを載せることは多くなるだろうし、巷のブログでよく見かける装飾されたプログラム表示をしてみたいなぁ、というのは自然の流れです(よね?)
さっそく調べてみると、有名なシンタックスハイライティングのスクリプトとして"SyntaxHighlighter"が見つかりました。
Bloggerへの導入も"integration"のページから参考になるリンクが多数あるので、すんなり導入できました。「デザイン」タブ→「HTMLの編集」→</head>前に、ここで紹介されているコードを置くだけで完了。
function substr_test() { var s = "0123456789"; alert(s.substr(-3)); }
ちゃんとシンタックスハイライティングされてますかね?
これでプログラムつきの記事が書けるようになりました!
そして、本題の記事はまた次回へと持ち越しになるのでした…
ブログはじめました
思い返すと、もともと多趣味な自分がテーマもなしに漠然と書きたいことをつらつら並べていただけで、「読んでもらう」ということはまったく念頭になかったのが結局長続きしなかった原因だったのでは?と思っています。
そこで、今回は技術ネタに絞ってブログを書いていこうと思います。ネタは常に乏しいかもしれませんが、「プログラミング」をしていて日々気づいたTipsなどを、自分の備忘録として、また、検索エンジンにでも引っかかって訪問されたかたのお役に立てれば幸いです。
当ブログの名前の由来ですが、私が愛読している"CodeUtopia"さんから「インスパイア」させていただきました。