文字列への文字単位のアクセスで波括弧が非推奨にかわった

ふと PHP のドキュメントを眺めていたら、次のように書かれていました
PHP: 文字列(English)

注意: $str{42} のように波括弧を使用してアクセスすることも可能です。 しかし、角括弧を使用する方法のほうが推奨されます。 なぜなら、{波括弧} 形式は PHP 6 で廃止される予定だからです。
 
Note: They may also be accessed using braces like $str{42} for the same purpose. However, using square array-brackets is preferred because the {braces} style is deprecated as of PHP 6.

PHP5 リリース前は

$str = “foo”; echo $str[0];

が非推奨で

$str = “foo”; echo $str{0};

が推奨されていましたが、方針転換をしたようです。
 
参考:
2004 年 3 月のマニュアル同項(English)(archive.org)

波括弧の後に任意の文字をゼロから始まるオフセットで指定することに より、文字列内の文字にアクセスすることが可能です。
 
    注意: 過去の互換性のため、配列括弧を使用することが可能です。しかし、 この構文はPHP 4に依存しています。
    
 Characters within strings may be accessed and modified by specifying the zero-based offset of the desired character after the string in curly braces.
  
    Note: For backwards compatibility, you can still use array-braces for the same purpose. However, this syntax is deprecated as of PHP 4.

以前はこうなっていました。

最新版の ffmpeg をダウンロードするには

ffmpeg とは、高機能な動画編集ツールです。

以前、この ffmpeg アプリのWindows版を探し回った事があったため、配布サイトをまとめてみました。
 
ffmpeg.org
公式サイト。
 
Windows用のffmpegコンパイル済バイナリは以下のサイトで配布されています。

ffmpeg 公式 Windows バイナリダウンロードページ:

https://ffmpeg.zeranoe.com/builds/

ダウンロードは、リンク先のボタンを押すだけです。

バージョンが古い可能性があるのであまりおすすめはしませんが、他にもフリーソフトに付属しているものを使うこともできます。
お気に入りの動画を携帯で見よう
SVN の HEAD を追いかけて Windows 用にビルドしたバイナリを配布しているサイト。
MingW での ffmpeg のビルド方法や依存するライブラリについても書かれています。
 
ImageMagick
ImageMagick は一部のビデオフォーマットを扱うために ffmpeg を使っているため、ffmpeg.exe をバンドルしています。
Windowsユーザでインストーラが不要な方はImageMagickのFTPサーバから、実行ファイルだけのダウンロードもできます。ファイル名が”ImageMagick-(バージョン番号)-Q16-windows.zip”のものがインストーラなし版です。
 
携帯動画変換君
ffmpegのインターフェイスとして動作するソフトです。ffmpeg が同梱されていますが、2010年9月現在、何年も更新されていないためバージョンは古めの様子。
 


Linux用 RPM は http://packages.sw.be/ffmpeg/ で最新版が順次配布されているようです。

バグパターン – switch のデータ型は複数種類にすると予期しない結果になる

まずはサンプルコードを見て、結果を予想してみてください。

<?php
$result = true;
switch($result){
  case “error”: // エラー
    echo “failure”;
    exit;
  case “ok”: // 成功
  case true: //
    echo “success”;
    exit;
  default:
    echo “unexpected”;
    exit;
}
?>

一見、このコードを実行すると success が出力されるように思いますが、実際に実行してみると意外なことに failure が出力されてしまいます。
PHP の switch 文は、switch の引数と case で指定した値とを= ではなく) でチェックしているため、switch 引数が複数の種類の型になる場合は型変換などにより予想外の値と一致することになってしまうのが原因です。
 
実際どの値が何と一致するかについては以下の検証コードを実行してみると分かります。

// 検証コード:
<?php
// values to test
$targets = array(
   0,
   1,
   true,
   false,
   null,
   “”,
   “0.00e5”,
   “10f”,
   “0f”,
   array(),
   array(1),
   array(“key”=>”foo”),
);
 
// —-
foreach($targets as $target){
  if(is_bool($target))
      $s = $target? “true”: “false”;
  elseif(is_null($target))
      $s = “null”;
  elseif(is_string($target))
      $s = “‘{$target}'”;
  else
      $s = $target;
  echo $s .”(“.gettype($target).”)”.”:\t”;
  switch($target){ //”0.00e5″
    case ‘a’: echo “case a”; break;
    case ‘b’: echo “case b”; break;
    case ‘0’: echo “case zero”; break;
    case 10: echo “case int 10”; break;
    case 0: echo “case int 0”; break;
    default: echo “default”; break;
  }
  echo “\n”;
}

php 4.4.6 および php 5.2.3 で試したところ、実行結果次のようになりました。

0(integer): case a
1(integer): default
true(boolean): case a
false(boolean): case zero
null(NULL): case int 0
”(string): case int 0
‘0.00e5′(string): case zero
’10f'(string): case int 10
‘0f'(string): case int 0
Array(array): default
Array(array): default
Array(array): default

同じ empty 値でも 0, null, false, “” で結果が全く異なってしまいました。
また、 == について挙げられる数値文字列の比較時の問題(“0.00e5” == “0” が真になる,など)の影響も受けてしまっています。
 
この問題は、型チェックを厳密にしたり、strval(), intval() などで明示的に文字列,数値キャストを行い、switch 文の引数の型が一種類になることを保証することである程度回避できます。
しかし依然として数値として有効な文字列同士の比較の問題があるため、数値を含む文字列について正確さが必要な場合や、本当に複数型を判別させたい場合は= 演算子を使い if – elseif – else を使うほうが賢明でしょう。

if($result = true || $result= “ok”){
  echo “success”;
}elseif(empty($result) || $result
= “error”){
  // empty($result) は以下の式と等価。
  // ( !isset($result) || ($result= false || $result = null ||
  // $result= “” || $result = 0 )
  echo “failure”;
}else{
  echo “unexpected”;
}

 
参考:
switch 構文(php.net)
比較演算子(php.net)
strval()(php.net)

SQL の JOIN の種類と違いまとめ — INNER/LEFT/RIGHT/FULL/CROSS

(2026年7月、内容を全面的に更新)

SQL でテーブルを結合する JOIN には、INNER JOIN・LEFT OUTER JOIN・RIGHT OUTER JOIN・FULL OUTER JOIN・CROSS JOIN の5種類があります。違いは一言でいえば「結合相手が見つからなかった行をどう扱うか」です。INNER は捨てます。LEFT/RIGHT/FULL は残して NULL で埋めます。CROSS はそもそも条件を付けず、全組み合わせを作ります。

答えとしてはこれで全部です。ただ、この一言だけを頼りに書いた SQL は、たいてい「思ったより行が少ない」「NULL の行はどこへ消えた」という形でつまずきます。そこでこの記事では、結合相手のいない行をわざと混ぜたサンプルデータに5種類の JOIN を順にかけて、結果がどう変わるかを目で確認していきます。あわせて結合条件の書き方(ON/USING/NATURAL)の違い、複数 JOIN の評価順、データベースごとの対応差(MySQL に FULL OUTER JOIN がない、など)もまとめます。

続きを読む SQL の JOIN の種類と違いまとめ — INNER/LEFT/RIGHT/FULL/CROSS

テーブルのディスク使用量を取得する

SELECT relname, relfilenode, relpages FROM pg_class;

relname がテーブル名、relfilenode が実体ファイル名、 relpages が利用しているページ数概算。1ページは通常 8KB です。
 

SELECT c2.relname, c2.relpages
    FROM pg_class c, pg_class c2, pg_index i
    WHERE c.oid = i.indrelid
        AND c2.oid = i.indexrelid
    ORDER BY relpages DESC;

同様にインデックスの利用しているページ数を取得します。
 
参考:
ディスク使用量の監視(PostgreSQL 8.2.5 公式マニュアル)
pg_class(同上)

アクセス中のファイルに対する他のプロセスでのファイル読み書き禁止を制御する

.NET, C++ ともに FileStream 等でのファイルアクセス時に FileShare という列挙体のメンバを追加で指定することでロック制御することができます。
 
http://msdn2.microsoft.com/ja-jp/library/system.io.fileshare(VS.80).aspx より引用:

FileShare 列挙体のメンバ
 
Delete:
  後続のファイルの削除を許可します。
Inheritable:
  ファイル ハンドルを子プロセスで継承できるようにします。Win32 では、直接サポートされません。
None:
  現在のファイルの共有を解除します。ファイルを閉じるまで、このプロセスまたは別のプロセスがファイルを開く要求をしても失敗します。
Read:
  後続の読み取り用のファイルを開くことを許可します。このフラグが指定されていない場合は、ファイルを閉じるまで、このプロセスまたは別のプロセスが読み取り用のファイルを開く要求をしても失敗します。ただし、このフラグが指定されていても、ファイルにアクセスするために追加のアクセス許可が必要になることがあります。
ReadWrite:
  後続の読み取り用または書き込み用のファイルを開くことを許可します。このフラグが指定されていない場合は、ファイルを閉じるまで、このプロセスまたは別のプロセスが読み取り用または書き込み用のファイルを開く要求をしても失敗します。ただし、このフラグが指定されていても、ファイルにアクセスするために追加のアクセス許可が必要になることがあります。
Write:
  後続の書き込み用のファイルを開くことを許可します。このフラグが指定されていない場合は、ファイルを閉じるまで、このプロセスまたは別のプロセスが書き込み用のファイルを開く要求をしても失敗します。ただし、このフラグが指定されていても、ファイルにアクセスするために追加のアクセス許可が必要になることがあります。

参考:
FileShare 列挙体(System.IO)
開くファイルへの他のプロセスからのアクセスを制限する(dobon.net)

ひこにゃんに学ぶ著作権

今朝ニュースを見ていたら、第二のおふくろさん騒動ともいえるニュースが流れていました。
 
ひこにゃんピンチ!…作者、彦根市に使用中止求める(YOMIURI ONLINE) より引用:

もへろんさん(22)が「適正なキャラクター管理を怠った」などとして、市と同祭実行委員会に祭終了後の使用中止を求める調停を彦根簡裁に申し立てたが、市は9日、ひこにゃんを今後も市のマスコットとして使用すると発表した。
 
 実行委は祭のキャラクターとして2006年1月、もへろんさんが応募したネコをモチーフにした3種類の図柄を採用。実行委が許可した団体の出版物などへの利用を許可してきた。
 
 しかし、申立書によると、実行委は「お肉が好物」「特技はひこにゃんじゃんけん」など作者の意図しないひこにゃんの性格づけをしたと主張。粗悪品が出回りかねないのに無制限に使用を承認しているなどとしている。

 
財産権である著作権を持つ彦根市に対して、作者のもへろん氏が著作者人格権のうちの同一性保持権を行使している形ですね。
 
著作権は譲渡可能ですが、著作者人格権は Wikipedia の言葉を借りると「一身専属性を有する権利であるため他人に譲渡できない」権利であるとされているため、勝手な性質の追加に対して異義を唱える事は妥当である、と思います。
 
しかし、前述の記事のように「祭終了後の使用中止を求め」たり、スポニチアネックスの記事にあるように、営利目的の利用や対して「相当額の支払いを求め」たりということまで要求できるかは、祭以外の利用や営利目的の利用が、著作者の名誉声望を害するかは微妙なところではないでしょうか。
 
今回の事例が教えてくれることは、クリエイター、デザイナー、エンジニアなど個人と企業の間での契約では、個人が作成した成果物の著作権は企業が所有する、という契約が多いと思いますが、この契約上でも個人が著作物に対して著作者人格権を行使することができるということです。
 
 ちなみに、プログラムについては「特定のコンピュータで利用できるようにしたり、より効果的に利用し得るようにするために必要な改変(Wikipedia)」であれば同一性保持権でいう改変にはあたりません。
 
とりあえず彦根市の問題については、ひこにゃんは個人的にも好きなキャラクターですし、町興し成功の好例なので、当事者間でうまく話がまとまるといいなと思っています。
参考:
著作権法(Wikipedia)
著作者人格権

サンプルコード – Cache_Lite のファクトリメソッド(マルチユーザ対応)

Cache_Lite は大変便利なのですが、Linux/BSD などで、複数実行ユーザが同じ cacheDir (たとえば /tmp/ )を使った場合に、他ユーザが作ったキャッシュへのアクセス権限が得られないため正しく動作しません。
Cache_Lite の hashedDirectoryUmask オプションと umask() 関数で 0777 を指定すれば十分な権限が得られますが、キャッシュの盗聴やかいざんの可能性が出てくるためセキュリティ的によろしくありません。
 
簡単な対応として思い付くのは

‘cacheDir’ => ‘~/tmp’,

のようにユーザのホームディレクトリにフォルダを分けてやることですが、
今回はより汎用的にするため、ファクトリメソッド内部でユーザ判別をしてフォルダを分けることでマルチユーザ対応させてみました。
 
# 暫定的な実装なので、不備があるかもしれません。

// This source is made available under the terms of the BSD license.
 
/**
 * Cache_Lite 用汎用ファクトリメソッド。
 * (PHP 4, 5 対応)
 * @version 2007-11-08
 */
class CacheLiteFactory {
  /**
   * @access private
   */
  function CacheLiteFactory(){
      // no-op
  }
  /**
   * static.
   * @access private
   * @param array $newOptions
   * @return options
   */
  function _defaultOptions($newOptions = null){
     // 初期デフォルト設定
     static $defaultOptions = array(
         // 必要なら設定可。
      );
      if(!empty($newOptions)){
          $defaultOptions = $newOptions;
      }
      return $defaultOptions;
  }
  
   /**
    * インスタンス化に使うデフォルトのオプションを設定します。
    * 過去に設定していたオプションは全て消去されます。
    * 一部のオプションのみ追加、変更したい場合は getDefaultOption() で現在のデフォルトオプションを取得して再設定してください。
    *
    * static
    * @access public
    * @param array $newOptions 置き換えるオプション
    * @return void
    */
   function setDefaultOptions($newOptions){
      CacheLiteFactory::_defaultOptions($newOptions);
   }
   
   /**
    * インスタンス化に使われるデフォルトのオプションを取得します。
    * static
    * @access public
    * @return array 現在設定されているデフォルトのオプション
    */
   function getDefaultOptions(){
      return CacheLiteFactory::_defaultOptions();
   }
  
  /**
   * Cache_Lite インスタンスを取得する。
   * 引数を指定した場合、デフォルトオプションをベースに引数のオプションを追加,変更します。
   *
   * static
   * @access public
   * @param array $overrideOptions 上書きするオプションの連想配列
   * @return Cache_Lite
   */
   function factory($overrideOptions = array()){
       require_once “Cache/Lite.php”;
       // デフォルト値。
       $options = CacheLiteFactory::getDefaultOptions();
       
       if($overrideOptions && is_array($overrideOptions)){
            $options = array_merge($options, $overrideOptions);
       }
       if(empty($options[‘cacheDir’])){
           $options[‘cacheDir’] = “/tmp/”;
       }
        
       // 他ユーザのキャッシュはアクセス権限が十分にない(umask 0777 にしても削除はできない)ので
       // posix_getuid() で uid が取得できる場合はユーザごとにフォルダを分けるようにしておく。
      // ※ Windows 環境または –disable-posix オプション付きでビルドした場合は取得できないことに留意
       if(function_exists(“posix_getuid”)){
           if(@mkdir($options[‘cacheDir’], 0777)){ // PHP4 互換のため recursive なし
               @chmod($options[‘cacheDir’], 0777);
           }
           $options[‘cacheDir’].=”cache_uid_”.posix_getuid().DIRECTORY_SEPARATOR;
       }
       @mkdir($options[‘cacheDir’]); // PHP4 互換のため recursive はなし
       return new Cache_Lite($options);
    }
}

 

// 用例
/* —
  // デフォルトを与えるかは任意
CacheLiteFactory::setDefaultOptions(array(
    // ‘cacheDir’=>’/path/to/tmp/’,
    ‘lifeTime’ => 24 * 60 * 60, // set 1 day by default
    ‘hashedDirectoryLevel’ => 1,
    ‘automaticCleaningFactor’=>100,
  ));
— */
 
$cache = CacheLiteFactory::factory();
$value = $cache->get(“foo”);
if($value === false){
  $value = date(‘Y/m/d H:i:s’);
  $cache->save($value);
}
echo $value . “\n”;

プロジェクト内ファイルが増えて Eclipse が重い

既存のバージョン管理されていない、それなりに大きい規模のプロジェクトを SVN でバージョン管理しようとしている今日この頃。
 
手始めに現状のリソースの一部を Eclipse(+Subclipse) に 1プロジェクトとしていれてプロジェクトまるごとリポジトリに突っ込んだ結果、SVN を見に行く処理の度に激しく重くなってしまいました。
 
現時点でプロジェクトフォルダ内にあるファイル数は約 50000 個、フォルダは約 2500個、データ量 1.85GB。
 
いくら Eclipse が昔に比べパフォーマンスがよくなったとはいえ、この数を扱うとさすがに重い。そのせいなのか同期に失敗したり(というか反映が激しく遅かったり)、ところどころ動作が怪しい。
 
このままでは作業に支障がでる、ということでリポジトリから部分チェックアウトして別個プロジェクトとして作業することにし、無事軽快さを取り戻しました。
.project を svnignore に追加しておけばリポジトリとの齟齬もありません。
 
難点は現状チェックアウトフォルダがプロジェクトルートじゃないと同期がとれなくなることでしょうか。ある親フォルダの、一部の子フォルダのみバージョン管理させたい場合は子フォルダごとにプロジェクトを分けるか、親フォルダでチェックアウトして svnignore で更新フォルダを限定するかのどちらかの対応しかなさそうです。
 
前者で対応する場合、作業セット(working set)(パッケージエクスプローラの右上の▽ボタン)を使うと、VS.NET のソリューションみたくパッケージエクスプローラの表示をフィルタリングできるのでよさそうです。
 
ナビゲーターフィルターもそれなりに使えそうですが、こちらは表示しないものを選択するネガティブフィルタリングであることと、編集が若干手間なのがネックです。
 
[[|Eclipseのナビゲーターのフィルターパターン追加http://fenrir.naruoka.org/archives/000530.html]](Fenrir’s BLog)

JavaSctript で信頼できる数値の範囲

JavaScript’s Defects on Numbers
 
Eclipse の Java2Script Pacemaker プラグイン開発者のブログより、
0×20000000000000 (54ビット)を超える値は信用できないよ、という記事。
以下ほぼ原文訳。


テストスクリプト:

javascript:alert (0x1ffffffffffffe);
javascript:alert (0x1fffffffffffff);
javascript:alert (0x20000000000000);
javascript:alert (0x20000000000001);

上記のテストスクリプトを実行すると、最後の二つの値が全く同等になることが確認できます(Firefox 2.0, IE 6.0 で確認)。
 
結論として、安全な数値範囲は -0x1fffffffffffff(-9007199254740991) から 0x1fffffffffffff(9007199254740991)までの範囲(正負それぞれ53ビット)です。Java から JavaScript への変換で、Java の long 値を JavaScript の数値に変換する時は演算結果が正しくなくなることがあります。
 


上の記事では J2S についてのみ書かれてるのだと思いますが、GWT でも該当するかもしれません。