refirio.org
気ままな雑記帳&実験場。好き勝手に色々やっています。
エントリー
タグ「PHP」の検索結果は以下のとおりです。
PHP5へ移行中
PHP Labo のプログラムをPHP5へ移行中…。(サーバーはロリポップ)
PHPの設定を .htaccess
でも ini_set()
でも変更できない問題は、一部の設定を php.ini で設定 で決定っぽい。
ということは、プログラムごとに設定を変更するのは不可能なのか…。しかも、php.ini
も一部の設定しか変更できないです。
upload_max_filesize
など、変更できない値はどうしようもないのかなぁ…。2M
で固定されてしまったのはちょっと痛い。
あと、PHP4では何もしなくても PEAR
が使えたけど、PHP5からは使えないみたい。
ちなみに、PHP Labo の新しいプログラムは、php.ini
編集画面で magic_quotes_gpc
を Off
に設定すれば問題なく動作するようです。(PEAR
は使っていないし。).htaccess
に書かれたPHPの設定は無視されるけど、大きな問題は無し。
PHP Labo では、php.ini
を以下のように設定しておいた。これでしばらく様子見…。
設定項目 | 設定内容 |
---|---|
default_charset | UTF-8 |
mbstring.language | Japanese |
mbstring.internal_encoding | UTF-8 |
mbstring.encoding_translation | Off |
mbstring.http_input | pass |
mbstring.http_output | pass |
magic_quotes_gpc | Off |
session.use_trans_sid | 0 |
short_open_tag | Off |
safe_mode | On |
MySQL&SQLite用のデータベース管理ツール(改良版)
以前に作成したデータベース管理ツールを改良しました。
PHP Labo のプログラムをPHP5用に書き換えるにあたり、簡易な管理ツールが欲しくなったので作成。以前作成したものを使えば大丈夫…と思いきや、PDOを使わないとSQLite3には接続できないので…。
そんな訳で、実行にはPHP5+PDOが必要です。また、以前は断念したデータのインポート機能も実装。なかなか便利。
詳細とダウンロードは以下のページから行えます。
PHP4→PHP5へ移行中
PHP Labo のプログラムを地道に書き換え中。PDO関連の修正が、単純な置換では対処できないので面倒。プラグインも含めると結構なファイル数になるなぁ…。
PHPと言えば、ロリポップがPHP5に対応するので大喜び…と思っていたけど、どうも色々問題があるようです。特に、PHPの設定を .htaccess
でも ini_set()
でも変更できないのは痛すぎる。
公式サイトには
現在、当該事項の対応・検証を行っております。
とか書かれているので、変更できるようになることを期待。というか、変更できなかったら使い勝手が悪すぎるので、サーバー引越しも検討しなければ…。
他の格安サーバーでは、何か問題は出ていないのかな…。
PDOの不具合
PDOのプレースホルダが意図したとおりに動作しません…。
$stmt = $pdo->prepare('SELECT * FROM address LIMIT ?, ?');
$flag = $stmt->execute(array(0, 5));
こんな風に書くと、SQLの文法エラーと言われてしまいます。
プレースホルダを文字で指定しても駄目。
$stmt = $pdo->prepare('SELECT * FROM address LIMIT :from, :to');
$flag = $stmt->execute(array(':from' => 0, ':to' => 5));
LIMIT句以外なら、普通にプレースホルダが機能するんだけどなぁ…。
ちなみに、bindValue()
で値を指定してから execute()
を実行するようにすればLIMIT句でも大丈夫だった。
$stmt = $pdo->prepare('SELECT * FROM address LIMIT ?, ?');
$stmt->bindValue(1, 0, PDO::PARAM_INT);
$stmt->bindValue(2, 5, PDO::PARAM_INT);
$flag = $stmt->execute();
文字で指定しても当然のように動作します。
$stmt = $pdo->prepare('SELECT * FROM address LIMIT :from, :to');
$stmt->bindValue(':from', 0, PDO::PARAM_INT);
$stmt->bindValue(':to', 5, PDO::PARAM_INT);
$flag = $stmt->execute();
なかなか原因が判らなかったけど、これはPDOの不具合らしい。
- PHP Bugs: #40740: PDO::execute() errors when parameters are used in LIMIT clause
- PDOでLIMIT句のプリペアードステートメントに関する不具合?
- PDOのLIMIT句が動作しない
何とも厄介な…。公式サイトには
PDO::execute() errors when parameters are used in LIMIT clause
と書かれているので execute()
の問題らしいけど、bindValue()
を使えばバージョンに関わらず実行できる…と思っていいのかな…。
うっかりミスでSQLインジェクションが起こり得ないようにするためにプレースホルダを使っている(僕の場合は)ので、「LIMIT句に値を渡すときだけ直接指定する」という書き方は極力避けたいのだけど。
PDOお試し中
概要だけは知っていたけど、実際に使うのは多分初めて。PEAR::DB
と同じような感覚で使えて良い感じです。
PDO
でのエラー処理は try
~ catch
で捕捉するのが定番みたいですが、PEAR::DB
みたいに戻り値のチェックで処理することもできるのですね。
PHP Labo のプログラムは非オブジェクト指向(手続き型)で書くので、エラー処理も昔ながらの方法にしようかなぁ…。その場合、こんな感じ?
<?php
try {
$pdo = new PDO(
'mysql:dbname=phpdb;host=localhost',
'user',
'pass',
array(
PDO::ATTR_ERRMODE => PDO::ERRMODE_SILENT
)
);
} catch (PDOException $e) {
exit($e->getMessage());
}
$stmt = $pdo->query('SELECT * FROM address');
if (!$stmt) {
list($state, $code, $message) = $pdo->errorInfo();
exit($state . ':' . $code . ':' . $message);
}
while ($data = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo $data['no'] . ':' . $data['name'] . "<br>\n";
}
?>
コンストラクタのエラーは try
~ catch
でしか補足できなかった。他に方法が無いか、後でもう少し調べてみます。でもやっぱり、データベースのエラーは全部 try
~ catch
で処理した方がスッキリ書けるかなぁ…。
今のところ使っていないけど、トランザクションを使う場合は特に便利だし。
また、SQLite2を使うかSQLite3を使うかで、コンストラクタに渡す値が微妙に異なります。うーん、設定ファイルでSQLite2、SQLite3、MySQLを切り替えるようにするかな。
PHP4→PHP5への移行
このサイトはロリポップを使用しているのですが、とうとうPHP5に移行するらしいです。ちなみに Web Liberty はWADAXを使用していますが、結構前にPHP5に移行済み。
その他のサーバーもPHP4が使えなくなるのは時間の問題だと思うので、PHP Labo のプログラムをPHP4非対応に修正していきます。
代わりに、PHP5で追加された機能を色々使います。PEARが不要になるので、設置も楽になるハズ。
そんな訳で、自分用に移行メモ。「オブジェクトのコピー方法が云々」とか紹介しているのではなくて、あくまでも PHP Labo のプログラムを修正するための自分用作業メモ。ちなみに、厳密にはPHP5.1以降への移行が前提になっています。
PEAR::DB
ではなくPDO
を使用する。opendir()
ではなくscandir()
を使用する。fopen()
+fwrite()
+fclose()
はfile_put_contents()
で処理できる。ただし、ロック方法などを後で調べる。fgetcsv()
はPHP4とは異なり日本語処理に難があるため、使い物にならなくなっている(ような気がする)。文字コードの問題っぽい?- セッションハイジャック対策に
session_regenerate_id(true)
を使用する。 - XMLの解析には
SimpleXML
が便利。 - 初期設定ではMySQLではなくSQLiteを使用するようにしておく。
思いついたら追加します。
あと、PHP5への移行と同時に、ちょっとだけ機能強化もする予定。
ようやく仕事が直接関係しないプログラミングができると思うと、何だかテンションが上がるぞ。
PHPでツリー表示プログラム
これも必要になったのでメモ。
<?php
function put_tree($no, $line, $broths, $childs, $texts) {
echo '<span class="line">' . $line . '</span>';
echo '▼[' . $no . ']' . $texts[$no] . '<br>';
$line = preg_replace('/├$/', '│', $line);
$line = preg_replace('/└$/', ' ', $line);
$no = isset($childs[$no]) ? $childs[$no] : 0;
while ($no > 0) {
$tail = $broths[$no] ? '├' : '└';
put_tree($no, $line . $tail, $broths, $childs, $texts);
$no = $broths[$no];
}
}
?>
<html>
<head>
<title>ツリー表示</title>
<style>
.line {
font-family: "MS ゴシック", monospace;
}
</style>
</head>
<body>
<?php
$logs = array(
array(1, 0, 'あああああ'), //記事番号・親記事番号・記事内容
array(2, 1, 'いいいいい'),
array(3, 1, 'ううううう'),
array(4, 2, 'えええええ'),
array(5, 3, 'おおおおお'),
array(6, 3, 'かかかかか'),
array(7, 0, 'ききききき'),
array(8, 6, 'くくくくく'),
array(9, 8, 'けけけけけ'),
array(10, 7, 'こここここ')
);
$roots = array();
$broths = array();
$childs = array();
$texts = array();
foreach ($logs as $log) {
list($no, $pno, $text) = $log;
if ($pno == 0) {
$roots[] = $no;
} else {
$broths[$no] = isset($childs[$pno]) ? $childs[$pno] : 0;
$childs[$pno] = $no;
}
$texts[$no] = $text;
}
rsort($roots);
foreach ($roots as $root) {
put_tree($root, '', $broths, $childs, $texts);
}
?>
</body>
</html>
実行結果は以下のとおり。
▼[7]ききききき
└▼[10]こここここ
▼[1]あああああ
├▼[3]ううううう
│├▼[6]かかかかか
││└▼[8]くくくくく
││ └▼[9]けけけけけ
│└▼[5]おおおおお
└▼[2]いいいいい
└▼[4]えええええ
ツリー生成手順は、以下の書籍を参考にしています。プログラミングをはじめた頃によく読んでいた本なので、久しぶりに読んで懐かしい…。
PHPで2ch互換トリップ生成
必要になったので自分用にメモ。トリップ生成時の文字コードはShift-JISにしておく。
<?php
$tripkey = '#istrip';? //パスワードとする文字列(# 付き)
$tripkey = substr($tripkey, 1);
$salt = substr($tripkey . 'H.', 1, 2);
$salt = preg_replace('/[^\.-z]/', '.', $salt);
$salt = strtr($salt, ':;<=>?@[\\]^_`', 'ABCDEFGabcdef');
$trip = crypt($tripkey, $salt);
$trip = substr($trip, -10);
$trip = '◆' . $trip;
echo $trip;
?>
トリップの概要とコードは以下のページを参考にしました。(参考というか、ほぼそのまま。)
ファイルロック解除処理
またもPHPでの排他処理について。ファイルに書き込みを行う場合は
$fp = fopen('data.txt', 'r+') or exit('error!');
flock($fp, LOCK_EX);
~ここで書き込みを行う~
flock($fp, LOCK_UN);
fclose($fp);
で問題ないと思ったけど、まだ駄目っぽい。ロックの解除に問題があり、ファイルの破損は完全に回避できないらしい。調べてみると色々出てきた。
fcloseの前にflock(ファイルポインタ, LOCK_UN) する人は実に多いのですが、これははっきりと間違いだと断言します。flockをfcloseの前に解除するということは、fcloseの前に他のプロセスが割り込む可能性が出るということです。ファイルへの書き込みは、fwriteとかfputsとかしてからfflushまたはfclose実行までのどこかで行われる、というのがファイル周りのI/Oの基本です。なので、fcloseもロックの範囲内に入れなければなりません。fcloseでflockが解除されるのはそういう理由があるのです。
PHP/ファイルロック/設計 - TestWiki - PukiWiki Plus!
プロセスレベルの書き込みバッファによって、書き込みデータがOSに渡されずに残っている可能性がある。
fflush($fp); flock($fp, LOCK_UN); fclose($fp);
で明示的にフラッシュするか、flock($fp,LOCK_UN)しないで
fclose($fp); // LOCK_UN してはならない
をすることで、バッファがフラッシュされた後、ロックが解除される。
ロックの解放には fclose() でを使用します (これは、スクリプトが終了した場合にも自動的にコールされます)。
公式サイトの解説は「ロックの解放には fclose() でを使用します」と書いている割に、サンプルコードでは flock($fp, LOCK_UN);
で解除しています。こんな風に書かれていたら、どっちでも大丈夫なのかと思ってしまうよ…。
公式サイトのサンプルコードは、あまり信用しないほうがいいのかなぁ…。公式サイトなのに。
ついでに書くと「でを使用します」って誤字ですよね…?
ともかく、ロックの解除は fclose()
にまかせて
$fp = fopen('data.txt', 'r+') or exit('error!');
flock($fp, LOCK_EX);
~ここで書き込みを行う~
fclose($fp);
が正しいっぽい。
データベースとファイル
PHPでデータベース対応のプログラムをいくつか作ってきましたが、データベースとファイルの両方に対応したプログラムを作成しようと考え中。PHP Labo のプログラムとは別に、1つ徹底的に高機能なプログラムを作りたいのです。
その際、データを扱う処理をどんなふうに書くか悩み中。
同じ命令でMySQLもSQLiteもファイルも扱えるような、有名どころのクラスがあればいいけど、どうも無いっぽい。うーん、プログラム内で単純に条件分岐して各処理を併記するかなぁ…。可読性が下がりそうで少し嫌だけど。
ユーティリティ
カテゴリー
タグクラウド
- 33分探偵1
- AMBITIOUS JAPAN!1
- ARIA2
- Air2
- Android2
- BLACK CAT2
- C#1
- Chrome2
- FINAL FANTASY2
- Flash2
- GAE1
- JavaScript18
- Kindle1
- Mac2
- MySQL7
- PHP68
- PayPal1
- Perl3
- PostgreSQL2
- Python1
- Ruby1
- SQLite6
- Switch1
- TinyMCE4
- Windows Media Player1
- bot1
- fragile1
- freo53
- iPhone3
- iTunes1
- levis1
- mod_rewrite2
- node.js1
- sola1
- true tears1
- いつかのメリークリスマス1
- いつか帰るところ1
- けいおん!1
- ここにしか咲かない花3
- とある魔術の禁書目録1
- とらドラ!2
- ひぐらしのなく頃に2
- みなみけ1
- イラスト4
- ガンダム003
- クロノトリガー1
- ザナルカンドにて4
- テラ1
- ニコニコ動画8
- ハゲタカ2
- ピアノ36
- マクロスF3
- ユニットテスト1
- ルパン三世1
- ローズ・オブ・メイ4
- 初音ミク1
- 半分の月がのぼる空1
- 名探偵コナン1
- 戦場のメリークリスマス5
- 携帯10
- 攻殻機動隊1
- 桜2
- 機工魔術士1
- 決行~姫をさがして~1
- 涼宮ハルヒの憂鬱10
- 深愛2
- 灼眼のシャナ4
- 聖剣伝説2
- 蕾3
- 蟲師2
- 返信2
- 野球1
- 鋼の錬金術師1