カテゴリー別アーカイブ: PHP

ApacheでPHPを使用して処理した大きなページを圧縮(mod_deflate使用)するとメモリリークする事がある(PHPの消費メモリが減らない)

 先日の本番サーバでの出来事。
 データ関連のエクスポートを行うPHPのプログラムがあって、とあるクライアントが非常に大きいデータ(数十MB)をダウンロードし始めた。
 この時監視していたところ、本番サーバのhttpdプロセスがメモリ(RES)を500MB程度使われていた。
 まぁ、データ量がデータ量だからそんな物かと思ったのだけど、該当プロセスのCPUが0%になってもメモリがそのまま解放されない。
とりあえず、こんなプロセスがたまったらいかに本番サーバといえどもメモリが吹き飛んでサービス停止に陥る(本来はリソース計画で最大状態でも足りるように制限設定するべきなんだけど、諸事情から出来ない・・・)ので、とりあえずApacheのMaxRequestsPerChildを下げてメモリが枯渇する前に再起動するようにした;

 本番データを開発環境に入れて同じリクエストを送ってみるがメモリはちゃんと解放される。
 PHPの問題かと思ったのだけど、いまいちわからず。
 仕方ないので、本番の直近バックアップイメージを仮想環境に立ち上げて、デバッグツールを入れて走らせると再現した。
 そのでかいデータ、DEFLATEされていたのだ。 コンテンツタイプがtextだったので、OutputFilterで圧縮処理をがりがりやってたのだが、データがある程度でかいと、この時に握ったメモリが解放されない(メモリリークしてる)
 開発環境はLANの帯域があるからDEFLATEしていなかった。
 とりあえず、該当処理のアドレスをDEFLATEの除外条件にした。 けど、大きい物ほど圧縮したいなぁと思うわけだけど・・・
 PHPのメモリを制限していても、DBに繋いで読んで出してを繰り返す場合にはPHP自身は変数(メモリ)を再利用しているからそこではメモリ消費が増えず、外のmod_deflateの中だけ増え続けちゃうから、大きいデータは別処理でちゃんと圧縮してからAttachしてダウンロードするように修正かな。

 まぁ、httpdがメモリを解放してくれない場合にはmod_deflateをチェックと、メモ。

(591)

カテゴリー: LAMP[Linux, Apache, MySQL, PHP], PHP, サーバ設定 | コメントをどうぞ

POSTしているページの「Webページの有効期限が切れています」を抑制する

 Webでブラウザバックした場合、「Webページの有効期限が切れています」等と出て、以前の入力内容が表示できないことがある。
 これは、ページリクエストがPOSTのページでキャッシュが無効になっている場合、再度POSTしないとページ内容が表示できないと言う事。
 最新の内容を表示させることを目的としていれば、この表示は妥当で、再度POSTしてもらうべきではあるが、入力ページなどで戻るボタンで移動したとき、前回の入力内容が表示できた方が便利だけど、この動作だとリロードになって入力内容がリセットされてしまうため、この動作を変更する。

 PHPでの実装は簡単で、
session_start()前

session_cache_limiter(‘private_no_expire’)

をセットすれば良い。

 これで、ページキャッシュが有効になって、ブラウザバックしたときには前回入力内容がそのまま表示される。

(666)

カテゴリー: PHP | コメントをどうぞ

PHPのUserAgent設定

 PHPでfile_get_contentsなんかを使うとURLからもGETすることが出来る。
 $html = file_get_contents(“http://hogehoge.tld/”);
 みたいな感じ。

 で、この時、UAはPHPが入るんだけど、最近、Google検索をPHPで叩きに行くと403Forbiddenになってしまう。 ここのUA文字列を書き換えると表示できるので、PHPに任意のUAをセットしたい。

 方法は簡単で、iniに設定する。
/etc/php.iniファイルを修正する場合は[PHP]セクションで
 user_agent = “Mosaic”
みたいに設定する。

実行時に切り替える場合は、ini_set関数で
 ini_set(‘user_agent’, ‘User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6)’);
みたいな感じにする。

 独自BOTを作っていて、BOTのUAを定義したい場合など役に立つだろう。

(767)

カテゴリー: PHP | コメントをどうぞ

Yahoo APIを利用して住所から座標を取得する – ジオコーダー 住所 座標 緯度 経度 PHP 開発 サンプル

 Yahoo APIのジオコーダーを利用して住所文字列から座標を調べてみる。

サンプル > 実行してみる

$Y_APPID = ”;//yahoo api 開発ID

$curl = curl_init();
$request_array = array(CURLOPT_URL => "http://geo.search.olp.yahooapis.jp/OpenLocalPlatform/V1/geoCoder?appid={$Y_APPID}&query=".urlencode("東京都千代田区"));
curl_setopt_array($curl, $request_array);
$res = curl_exec($curl);
$xml = simplexml_load_string($res);
list($lon,$lat) = explode(",", $xml->Feature->Geometry->Coordinates);
echo("<p>該当した住所:".$xml->Feature->Name."<br /><li>緯度:{$lat}</li><li>経度:{$lon}</li></p>");

(763)

カテゴリー: PHP | コメントをどうぞ

Yahoo APIを利用して形態素解析 – 文字列 文節解析 構造解析 PHP 開発 サンプル

 Yahoo APIの形態素解析(文書の構成を解析する)をPHPから使ってみる。

サンプル > 実行してみる

$Y_APPID = ""; //yahoo api 開発ID
$sentence = "テスト文書について、形態素解析をかけることでキーワードを抽出してみる。";
$POST_REQUEST = "appid={$Y_APPID}&results=ma&sentence=".urlencode($sentence);

$defaults = array(
    CURLOPT_POST => 1,
    CURLOPT_HEADER => 0,
    CURLOPT_URL => "http://jlp.yahooapis.jp/MAService/V1/parse",
    CURLOPT_FRESH_CONNECT => 1,
    CURLOPT_RETURNTRANSFER => 1,
    CURLOPT_FORBID_REUSE => 1,
    CURLOPT_TIMEOUT => 0,
    CURLOPT_POSTFIELDS => $POST_REQUEST
);
$ch = curl_init();
curl_setopt_array($ch, $defaults);
$res = curl_exec($ch);
curl_close($ch);
$xml = simplexml_load_string($res);
$WordsArray = array();
$WordsHashToWord = array();
foreach ($xml->ma_result->word_list->word as $cur){
    if($cur->pos == "名詞"){
        @$WordsArray[md5($cur->surface)]++;
        @$WordsHashToWord[md5($cur->surface)] = $cur->surface;
    }
}
arsort($WordsArray);
$i = 1;
echo("<ol>");
foreach($WordsArray as $w=>$n){
    echo("<li>{$WordsHashToWord[$w]}[{$n}]</li>");
    if($i++ >= 10) break;
}
echo("</ol>");

 公式サンプルはGETだけど、長さ制限があるので、CURLを利用してPOSTしている。
 最初に入力された文書をYahooに解析してもらって、品詞を登場頻度の多い順に表示する。
 例えば、先日のSimpleHTML DOM Parserで拾ったHTMLのBODYを形態素解析して品詞の多い順に解析すれば、ページのキーワード傾向を調べることが出来る。

 先日から色々紹介しているPHPサンプルだが、共用レンタルサーバだとモジュール不足で使えないことも多いので、VPSの利用をお勧めしたい。

(499)

カテゴリー: PHP | コメントをどうぞ

PHPでHTMLを簡単に扱う – SimpleHTML DOM Parser

 PHPでHTMLを扱うときに便利なのがSimple HTML DOM Parserと言うライブラリ。
 HTMLが正しい構造ならば、PHP標準のXML機能で扱えるんだけど、世の中、正しくないHTML文書の方が多いので、パースで転けるけど、このライブラリを使うとブラウザのように上手く理解してくれるので、簡単に扱うことが出来る。

 file_get_html(url)でHTMLをパースしたオブジェクトを得て、そのオブジェクトに対してfind(タグ名)メソッドや、children(要素番号)メソッドでタグを分割できる。

サンプル > 実行してみる on さくらのVPS

require_once(‘simple_html_dom.php’);
$URL = ‘http://vps.xn--ockc3f5a.com/’;

if($html = file_get_html($URL)){
    $linka = array();
    $links = array();
    foreach($html->find(‘a’) as $el){
        $linka[md5($el->href)]++;
        $links[md5($el->href)] = $el->href;
    }
    arsort($linka);
    foreach($linka as $k=>$n){
        echo("<li>{$links[$k]} [{$n}リンク]</li>");
    }
}else{
    echo(‘HTMLの取得に失敗しました’);
}

 この場合、全てのaタグを探索して、そのhref要素についてカウントしている。
 正規表現を使って^http[s]{0,1}:\/\/で切り分けてやれば、相対リンクと絶対リンクの切り分けが出来るだろう。
 更に、絶対リンクを^http:\/\/vps.xn--ockc3f5a.com\/で切り分けると内部リンクと外部リンクに分けられる。

 CでHTMLをパースする場合は、こちらの記事が参考になる。

(243)

カテゴリー: PHP | コメントをどうぞ

CodeIgniterのルーティングを活用する – PHP 開発

 CodeIgniterのルーティングの話。
 ルーティングは、URIルールに従って動くCodeIgniterのコントローラ制御などのルールを書き換えて、本来と違う動きを挿せる機能。

$route[‘PRO/([^\/]+)’] = “$1/index/pro”;
$route[‘PRO/([^\/]+)/([^\/]+)’] = “$1/$2/pro”;
$route[‘PRO/([^\/]+)/([^\/]+)/(.*)’] = “$1/$2/pro/$3”;

$route[‘PREMIUM/([^\/]+)’] = “$1/index/premium”;
$route[‘PREMIUM/([^\/]+)/([^\/]+)’] = “$1/$2/premium”;
$route[‘PREMIUM/([^\/]+)/([^\/]+)/(.*)’] = “$1/$2/premium/$3”;

 これらのルーティングを定義すると、通常、 /Controller/Method/Options… となっているURIを書き換えて、製品グレード別に /PRO/Controller/Method/Options… /PREMIUM/Controller/Method/Options… のようにアクセスさせて、内部的には同じ /Controller/Method/製品グレード/Options… にマップする。
 各メソッドの第一引数に製品グレードを判別して、使える機能・使えない機能を切り分けたりすることが出来る。

(407)

カテゴリー: LAMP[Linux, Apache, MySQL, PHP], PHP | コメントをどうぞ