HTTP_Request を使用してファイルをアップロードする方法
1PEAR の HTTP_Request を使用してファイルをアップロードする方法です。
<form action='POST_URL' method='post' enctype='multipart/form-data'> <input type='text' name='title'> <textarea name='body'></textarea> <input type='file' name='upload_file'> <input type='submit'> </form>
上記のような HTML でファイルをアップロードする場合と同じような処理をするには、下記のように HTTP_Request を使用します。
// POST パラメータ $post_data = array( 'title' => $title, 'body' => $body, ); // アップロードパラメータ $upload_file = array( 'name' => 'file', 'path' => '/path/to/file', ); // アップロード $rs = http_send(POST_URL, $post_data, $upload_file); function http_send($url, $params, $upload_file=null) { $req = new HTTP_Request(); $req->setMethod(HTTP_REQUEST_METHOD_POST); foreach ($params as $key => $val) { $req->addPostData($key, $val); } $req->setURL($url); if ($upload_file) { $res = $req->addFile($upload_file["name"], $upload_file["path"]); if (PEAR::isError($res)) { echo $res->getMessage(); exit; } } if (!PEAR::isError($req->sendRequest())) { return $req->getResponseBody(); } else { return false; } }
PostgreSQL のバックアップとリストア
1PostgreSQL のバックアップとリストア方法のメモ
postgres ユーザになる
$ su - postgres
パスワードを設定していれば聞かれるので入力する。(当然ですが)
データのバックアップ
$ pg_dump DATABASE_NAME > BACKUP_FILENAME
データのリストア
$ psql -e DATABASE_NAME < BACKUP_FILENAME
データベースの作成
$ createdb DATABASE_NAME
データベースの削除
$ dropdb DATABASE_NAME
phpPgAdmin でログインできない
0普段は MySQL ばかり使用しているのですが、PostgreSQL を使用する必要があり、phpPgAdmin を使うことにした。
開発用のサーバには phpPgAdmin がインストールされているが、ブラウザで閲覧できるようにはまだしていなかった。
Open Tech Press | phpPgAdmin:Web開発者向けのPostgresクライアントツール を参考に /usr/share/phpPgAdmin にインストールされている phpPgAdmin をブラウザでアクセス可能にした。
/etc/http/conf/httpd.conf に下記を追加
Alias /phppgadmin /usr/share/phppgadmin/ <DirectoryMatch /usr/share/phppgadmin/> Options +FollowSymLinks AllowOverride None order deny,allow deny from all allow from localhost </DirectoryMatch>
これでブラウザから http://example.com/phpPgAdmin/ でアクセスできるようになった。
しかし、PostgreSQL のユーザでログインしようとするとエラーになる。
これは シン石丸の電脳芸事ニッキ: debian 3.1へのphppgadminのインストール後の設定 を参考にして解決。
/etc/postgresql/pg_hba.conf に下記を追加
host all all 127.0.0.1 255.255.255.255 trust
これで無事 phpPgAdmin にログインできました。
CakePHP Security コンポーネントのまとめ
1CakePHP の Security コンポーネント の動作を調べたのでまとめておきます。
この Security コンポーネントをうまく使用すればクロスサイトリクエストフォージェリ(CSRF) を防ぐことができるでしょう。
トークンの使用
フォームにワンタイムトークンを実装する方法です。
コントローラの beforeFilter メソッドでトークンをチェックするアクションを指定
function beforeFilter() { $this->Security->requireAuth('login'); }
ビューのフォーム内にトークンを設定
<?php echo $html->formTag(); ?>
トークンが hidden 属性で生成される
トークンが一致しない場合
requireAuth で指定したアクションに POST でアクセスがあるとセションに保存したトークンとフォームから送られてきたトークンが一致するかチェックします。またそのほかにトークンの有効期間もチェックします。有効期間は CAKE_SECURITY の設定により違います。
CAKE_SECURITY | 有効期間 |
---|---|
high | 10分 |
medium | 100分 |
low | 300分 |
トークンが一致しないと SecurityComponent の blackHole メソッドが実行されます。このメソッドでは
header('HTTP/1.0 404 Not Found');
を出力して exit します。(画面は空白)
任意の処理を実行したい場合は blackHoleCallback でコールバック関数を指定します。
設定できるのは同じコントローラ内のアクションのみになります。
function beforeFilter() { $this->Security->blackHoleCallback = "securityError"; $this->Security->requireAuth('login'); } function securityError() { die("security error!"); }
トークンチェックをするアクションを複数指定するときはカンマでつなげる
$this->requireAuth('login', 'delete');
特定のコントローラからのポストのみ許可する
$this->Security->allowedControllers = array("users");
これを指定するとたとえトークンが一致しても許可のないコントローラからのポストの場合は blackHole メソッドを実行します。
特定のアクションからのポストのみ許可する
$this->Security->allowedActions = array("action");
これを指定するとトークンが一致しても許可のないアクションからのポストの場合は blackHole メソッドを実行します。
ポストのみ受け付けるようにする
$this->requirePost('login');
これはトークンとは違い、POST のみ許可して GET でのアクセスを不可にします。
/users/login/ のような URL でのアクセスも GET なので不可になります。
POST の処理だけを実行したいようなアクションに使用します。
CakePHP Textヘルパーの truncate を全角文字に対応させてみた
5CakePHP の Text ヘルパーに truncate という指定された文字列を任意の長さに省略するメソッドがあります。
しかし、このメソッドは全角文字を考慮していないため全角文字に用いると文字化けすることがあります。
そこでこのメソッドを全角文字に対応させてみました。
function truncate($text, $length, $ending = '…', $exact = true) { if (strlen($text) < = $length) { return $text; } else { mb_internal_encoding("UTF-8"); if (mb_strlen($text) > $length) { $length -= mb_strlen($ending); if (!$exact) { $text = preg_replace('/\s+?(\S+)?$/', '', mb_substr($text, 0, $length+1)); } return mb_substr($text, 0, $length).$ending; } else { return $text; } } }
直接 Text ヘルパーを修正するとバージョンアップなどのときに困るので、
cake/libs/view/helpers/text.php を app/views/helpers/mb_text.php にコピーしクラス名を
class MbTextHelper extends Helper{
として、truncate メソッドを上記のように修正しました。
使用するときはコントローラ内で、
var $helpers = array("MbText");
view で
echo $mbText->truncate("あいうえおかきくけこ", 5, "…", true);
とすると
あいうえ…
と表示されます。
CakePHP find や findAll の条件指定にちょっとだけ便利な postConditions
1CakePHP の コントローラに postConditions というちょっとだけ便利なメソッドがありました。
cake/libs/controllers.php
function postConditions($data) { if (!is_array($data) || empty($data)) { return null; } $conditions = array(); foreach($data as $model => $fields) { foreach($fields as $field => $value) { $conditions[$model . '.' . $field] = $value; } } return $conditions; }
例えば検索をするフォームなどで User.name で検索するような場合
view で
input('User/name');
と指定すると$this->data は
Array ( [User] => Array ( [name] => 山田 ) )
この $this->data を postConditions に渡すと
$data = $this->postConditions($this->data);
$data は
Array ( [User.name] => 山田 )
となり、このまま find や findAll に渡すことができます。
$this->User->find($data);
参考:CakePHP マニュアル
7.2. コントローラの関数
11月に読んだ本
2最近は仕事関係の本や自己啓発関係の本が多い。特に今年は小説を読んでないので、今月は少し小説を読もうと思っています。
決算書がスラスラわかる 財務3表一体理解法 (朝日新書 44) (朝日新書 44)
あたりまえだけどなかなかできない仕事のルール (アスカビジネス)
ウェブ時代をゆく ─いかに働き、いかに学ぶか (ちくま新書 687)
なぜ、エグゼクティブはゴルフをするのか?
ちょいデキ! (文春新書 591)
すごい「実行力」
なぜ、エグゼクティブはゴルフをするのか?
仕事に活かす!本200%活用ブック
WEB+DB PRESS Vol.41
お金は銀行に預けるな 金融リテラシーの基本と実践 (光文社新書)
プログラミングPHP 第2版
CakePHPガイドブック
忙しいパパのための子育てハッピーアドバイス
ケータイ業界52人が語る「戦略」の裏側
カリスマ・コンサルタントの稼ぐ超思考法 ~仕事と人生に効く「問題解決力」が身につく20の方法~
自転車生活の愉しみ
GoogleMap 特定のキーワードで表示させる
4Google AJAX Search API を使用してキーワードや住所から自分のサイトに Google Map を表示させるメモ
Google AJAX Search API KEY と Google Map API KEY を指定して JavaScript を読み込む
<script src="http://www.google.com/uds/api?file=uds.js&v=1.0&key=Google AJAX Search API KEY" type="text/javascript"></script> <script src="http://maps.google.com/maps?file=api&v=2.x&key=Google Map API KEY" type="text/javascript"></script>
実際の表示部分。 q=キーワードで表示させる地図のキーワード(または住所)を指定する。
<script type="text/javascript"> <!-- var gls; var gMap; function OnLocalSearch() { if (!gls.results) return; var first = gls.results[0]; var point = new GLatLng(parseFloat(first.lat), parseFloat(first.lng)); var zoom = 15; gMap.addControl(new GSmallMapControl()); gMap.addControl(new GMapTypeControl()); gMap.setMapType(G_MAP_TYPE); gMap.setCenter(point, zoom); var marker = new GMarker(point); gMap.addOverlay(marker); GEvent.addListener(marker, "click", function() { marker.openInfoWindowHtml(html); }); } function load() { gMap = new GMap2(document.getElementById("map")); gMap.addControl(new GSmallMapControl()); gMap.addControl(new GMapTypeControl()); gMap.setCenter(new GLatLng(0, 0)); gls = new GlocalSearch(); gls.setCenterPoint(gMap); gls.setSearchCompleteCallback(null, OnLocalSearch); var q = "横浜ランドマークタワー"; gls.execute(q); } //--> </script> <body onLoad="load()"> <div id="map" style="width: 410px; height: 320px"></div> </body>
各 API KEY の取得は下記ページから
Sign-up for an AJAX Search API Key – Google AJAX Search API – Google Code
Sign Up for the Google Maps API – Google Maps API – Google Code
CakePHP 環境によってデータベースを切り替える
2テストデータを入れるなどテストと環境でデータベースを切り替えたいときがあります。
CakePHP でそれをやる方法です。
モデルの $useDbConfig に app/config/database.php で定義されている $default がデフォルトで使用されます。
database.php に $test など使用したいデータベースの分だけ定義を増やし、
それをモデルで
$this->useDbConfig = 'test';
のように指定すればいいだけです。
app/app_model.php のコンストラクタで設定するのが一番簡単かもしれません。
CakePHP 環境に応じてDBの設定を変える | Shin x blog
で色々な方法が紹介されています。
“CakePHPで超簡単スケーラビリティ” フォーラム – CakePHP Users in Japan
また、この $useDbConfig を使用して
「マスターとスレーブのMYSQLサーバがあります。レプリケーション機能で、マスターからスレーブにデータが常にコピーされています。データの更新・追加はマスターに対して行い、データの検索はスレーブで、という場合にはどうすればよいでしょうか?」
というような場合のすごく簡単な方法が紹介されています。
モデルの beforeSave,afterSave,beforeDelete,afterDelete を使用してマスターとスレーブを切り替えています。
CakePHP MySQL で文字化けを防ぐ設定
4MySQL で文字化けを防ぐためには
SET NAMES utf8
のように SET NAMES を実行するのが有効なのですが、これを app/config/database.php で設定する方法です。
'encoding'=>'文字コード'
をデータベースの設定項目に追加してやるだけです。
具体的には app/config/database.php が下記のようになります。
var $default = array( 'driver' => 'mysql', 'connect' => 'mysql_connect', 'host' => 'localhost', 'login' => 'user', 'password' => 'password', 'database' => 'dbname', 'prefix' => '', 'encoding' => 'utf8' );
cake/libs/model/dbo/dbo_mysql.php で下記のように実行されています。
function connect() { (略) if (isset($config['encoding']) && !empty($config['encoding'])) { $this->setEncoding($config['encoding']); } return $this->connected; }
function setEncoding($enc) { return $this->_execute('SET NAMES ' . $enc) != false; }