PHPのODBC関数を使うときの注意点

PHPODBC関数でプリペアードステートメントを使うには
odbc_prepare, odbc_executeの2つの関数を使います。

例1

<?php
$a = 1;
$b = 2;
$c = 3;
$stmt    = odbc_prepare($conn, 'CALL myproc(?,?,?)');
$success = odbc_execute($stmt, array($a, $b, $c));

odbc_executeの第2引数にはパラメータの配列($parameters_array)を渡す。

ただし、次のような注意点がある。

parameter_array の中でシングルクォートで括られたデータがある場合、 それはファイル名と解釈されます。そのファイルの内容が、 該当するプレースホルダのデータとしてデータベースサーバに送信されます。


だから

シングルクォートで括られたデータを純粋に文字列として使用したい場合は、 空白などの別の文字を前後に付加する必要があります。 それにより、パラメータがファイル名とみなされることがなくなります (もしこのオプションが不要なら、別の仕組み、たとえば odbc_exec() で直接クエリを実行するなどを使用する必要があります)。

つまり、「''でくくられた文字列をファイル名とみなす」という特例を必要としない場合*1例1のコードはそのままの形で使用することはできない。
次のような「'で始まり'で終わる文字列の末尾に空白を付ける関数」なりなんなりでパラメータをエスケープしなければならない。


例2

<?php
function odbc_escape_params ($params) {
 if (!is_array($params) or empty($params)) {
  return array();
 }
 foreach ($params as $key=>$val) {
  if (strlen($val) > 1 and $val{0} == "'" and $val{strlen($val)-1} == "'") {
   $params[$key] .= ' ';
  }
 }
 return $params;
}

これでとりあえずしのげはするが、''でくくられた文字列をそのままの形でDBに収めることは結局できてないわけだ。。。はあ。。。



参考・引用元: PHPマニュアル
http://www.php.net/manual/ja/function.odbc-execute.php

*1:ほとんどの人はそうだろう

php-modeからPHP Manualを開く

Emacsにはデフォルトでphp-modeあるけどまずインデントからしておかしいのでこっち使いましょう、ってのが前提。
PHP mode for Emacs http://php-mode.sourceforge.net/


このphp-mode、マニュアルへのジャンプ機能があるみたい。
C-cRETでマニュアルのトップページへジャンプ、
C-cC-fでカーソル位置の単語についての説明ページを開いてくれます。


そのままだと英語のページが開きますが、
設定すれば日本語のPHPマニュアルが開けます。

<?php
(setq php-search-url "http://www.php.net/ja/")
(setq php-manual-url "http://www.php.net/manual/ja/")

PHPの->がよくわからない

array_map($func, $array)じゃなくて$array->map($func)って書きたいよなあと思ってちょっとやってみたんだけど、チェーンすると

PHP Fatal error:  Unsupported operand types in ...

ってなる。なんでだろう。

<?php
class MyArray {
  private $array;

  public function __construct() {
    $this->array = func_get_args();
  }

  public function map($func) {
    return new MyArray(array_map($func, $this->array));
  }

  public function copy() {
    return new MyArray($this->array);
  }

}

$array = new MyArray(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
$double = function ($x) {
  return 2 * $x;
};

var_dump($array->map($double));
var_dump($array->map($double)->copy()); //これはできる
var_dump($array->copy()->map($double)); //これはできない

関数渡すとだめだったりすんのかなあ。わからん。

PHPのuse

#wpscala にて、Scalaでは「1から100までの素数」がこれで得られますよー、ってのをやったんだけど

(0 to 100).filterNot(n => (2 until n).exists(n % _ == 0))

\ キャー、みじかーい /



そこでPHPでやってみようと思った。
ちょうど仕事で使うPHPのバージョンがやっと5.3になったので無名関数を使ってみたかったのです。

<?php
print_r(array_filter(range(1, 100),
                     function ($a) {
                       if ($a == 1) return true;
                       return ! array_filter(range(2, $a - 1),
                                             function($b) use ($a) {
                                               return $a % $b == 0;
                                             });
                     }));

これはひどい


まあともかくPHPクロージャを作ったり、親?のスコープで定義されてる変数を見たいときはuseというキーワードを使うらしい。

PHP: 無名関数 - Manual http://php.net/manual/ja/functions.anonymous.php

無名関数=クロージャっていう堂々としたスタンスのPHP△!

PHPのstrtotime()がなんだかすごい

PHPのstrtotime()関数は
英文形式の日付をいい感じにUnixタイムスタンプに変換してくれます。
最高にきもい便利です。


たとえば

<?php
echo strtotime("now"), "\n";
?>

これで現在のタイムスタンプが取得できます。
なんだかこれだけ見てもPHPのかほりがしますね。


一日後、一週間後のタイムスタンプがほしいなあ、ってときは

<?php
echo strtotime("+1 day"), "\n";
echo strtotime("+1 week"), "\n";
?>

これでいけます。


混ぜてもいけます。

<?php
echo strtotime("+1 week 2 days 4 hours 2 seconds"), "\n";
?>
<?php
echo strtotime("10 September 2000"), "\n";
?>

こういうのもOK。これはその日の0時のタイムスタンプを返します。


まあこのくらいならわかるけど、

<?php
echo strtotime("next Thursday"), "\n";
echo strtotime("last Monday"), "\n";
?>


ここまで来るとさすがって感じがしますね。


で、もしかしてできるんじゃね?って思って適当に

<?php
echo strtotime("today"), "\n";
echo strtotime("yesterday"), "\n";
echo strtotime("tomorrow"), "\n";
?>


ってやったらできました。


でも

<?php
echo strtotime("tommorrow"), "\n";
?>

スペルミスするとfalseが返ってくるので注意しましょう。

PHP + flymake

phpでflymake使おうと思ったんだけど
flymakeの設定のしかた調べるのめんどかったから
適当にネット徘徊して設定パクろうと思った。


メモメモ
ついでにjsとrubyのもくっついてますね。
VimからEmacsに乗り換えたので便利機能紹介します - 八発白中

(when (require 'flymake nil t)
  (global-set-key "\C-cd" 'flymake-display-err-menu-for-current-line)
  ;; PHP
  (when (not (fboundp 'flymake-php-init))
    (defun flymake-php-init ()
      (let* ((temp-file (flymake-init-create-temp-buffer-copy
                         'flymake-create-temp-inplace))
             (local-file (file-relative-name
                          temp-file
                          (file-name-directory buffer-file-name))))
        (list "php" (list "-f" local-file "-l"))))
    (setq flymake-allowed-file-name-masks
          (append
           flymake-allowed-file-name-masks
           '(("\.php[345]?$" flymake-php-init))))
    (setq flymake-err-line-patterns
          (cons
           '("\(\(?:Parse error\|Fatal error\|Warning\): .*\) in \(.*\) on line \([0-9]+\)" 2 3 nil 1)
           flymake-err-line-patterns)))
  ;; JavaScript
  (when (not (fboundp 'flymake-javascript-init))
    (defun flymake-javascript-init ()
      (let* ((temp-file (flymake-init-create-temp-buffer-copy
                         'flymake-create-temp-inplace))
             (local-file (file-relative-name
                          temp-file
                          (file-name-directory buffer-file-name))))
        (list "/usr/local/bin/jsl" (list "-process" local-file))))
    (setq flymake-allowed-file-name-masks
          (append
           flymake-allowed-file-name-masks
           '(("\.json$" flymake-javascript-init)
             ("\.js$" flymake-javascript-init))))
    (setq flymake-err-line-patterns
          (cons
           '("\(.+\)(\([0-9]+\)): \(?:lint \)?\(\(?:Warning\|SyntaxError\):.+\)" 1 2 nil 3)
           flymake-err-line-patterns)))
  ;; Ruby
  (when (not (fboundp 'flymake-ruby-init))
    (defun flymake-ruby-init ()
      (let* ((temp-file (flymake-init-create-temp-buffer-copy
                         'flymake-create-temp-inplace))
             (local-file (file-relative-name
                          temp-file
                          (file-name-directory buffer-file-name))))
        '("ruby" '("-c" local-file)))))
  (add-hook 'php-mode-hook
            '(lambda () (flymake-mode t)))
  (add-hook 'js-mode-hook
            (lambda () (flymake-mode t)))
  (add-hook 'ruby-mode-hook
            (lambda () (flymake-mode t))))

followerの一覧を取得するPHPスクリプト

http://github.com/abraham/twitteroauth
↑これ使いました。

<?php
require_once("twitteroauth.php");
$consumer_key = "[consumer_key]";
$consumer_secret = "[consumer_secret]";
$access_token = "[access_token]";
$access_token_secret = "[access_token_secret]";

$to = new TwitterOAuth($consumer_key,$consumer_secret,$access_token,$access_token_secret);

$next_cursor = -1;

do{
  $req = $to->OAuthRequest("https://api.twitter.com/1/statuses/followers.xml",
			   "GET",
			   array("cursor"=>"$next_cursor"));
  
  $xml = simplexml_load_string($req);
  $next_cursor = $xml->next_cursor[0];

  foreach($xml->users->user as $user){
    $screen_name = $user->screen_name;
    print $screen_name . "\n";
  }
}while($next_cursor != 0);
?>

りむったー、ってあるけどあれってどうやってんのかなーと思って。
自分だったらcronでこれ走らせてdiff取るかなあとか。

しっかしPHPは楽だなあ。