Category Archives: 開発備忘録 - Page 2

androidで複数のMapViewを使う場合の注意点

androidで複数のActivityで別々のMapViewを持っている場合に、戻るボタンで戻ってきた時に、前の画面でのMapViewのレイアウトが引き継がれてしまう事があって嵌ったので覚書。

元々adroidでは1つのアプリの中で使用できるMapViewは1つだけらしく、別のActivityでもMapViewのインスタンスは使いまわされているみたい。(詳細未確認)

解決策としては、戻ったActivityのonResume 内で、MapView#requestLayout() を呼んでやると直る。
こんな感じ。

public void onResume(){
  super.onResume();
  MapView mapView = (MapView) findViewById(R.id.MapView);
  mapView.requestLayout();
}

普通によくありそうな事なのに、なかなか情報が見つからなかった、、、。

androidエミュレータからlocalhostへの接続

androidの開発でlocalhostへの接続ではまったので覚書を。
androidから外部APIなどへの接続って言うのは良くあると思いますが、開発時にローカルに開発用サーバーを準備してそこへ接続って言うのは良くやると思います。
ここで、Webアプリの開発をやっている人は(僕もそうですが)うっかり、接続先のホスト名をlocalhost 又は 127.0.0.1 としてしまいそうですが、これだと接続でしません。
connection refused とか言われてしまいます。
AVDから見たlocalhostはAVD自身になるそうです。
その代わりにローカルPCには、10.0.2.2 というIPが割り当てられているようです。
なので、これをURLとして指定してあげると接続できます。
考えてみれば当然のことのようですが、やりががちな間違いです。

cakePHPのimageBehaviorについて

こちらの
http://blog.syuhari.jp/archives/1905
記事でimageBehaviorというのを知り、早速使っていました。
findしたときにも、各画像のパス結果レコードに挿入してくれて便利なのですが、どうやらリレーションテーブルのiに関しては処理してくれないようです。
なので、上記ソースに少し手を入れて、belongsToのテーブルに関しても持ってきてくれるように追記してみました。
即席なのでおかしなところがあったらご指摘いただけるとありがたいです。


<?php

class ImageBehavior extends ModelBehavior {

	var $settings = null;

	function setup(&$model, $config = array()) {
		$this->imageSetup($model, $config);
	}

	function imageSetup(&$model, $config = array()) {
		$settings = Set::merge(array(
		'baseDir'=> '',
		), $config);

		if (!isset($settings['fields'])) $settings['fields']=array();
		$fields=array();
		foreach($settings['fields'] as $key=>$value) {
			$field = ife(is_numeric($key), $value, $key);
			$conf = ife(is_numeric($key), array(), ife(is_array($value),$value,array()));
			$conf=Set::merge(
			array (
				'thumbnail' => array('prefix'=>'thumb',
					         'create'=>false,
					         'width'=>'100',
 					         'height'=>'100',
 					         'aspect'=>true,
							 'allow_enlarge'=>true,
		                    ),
				'resize'=>null, // array('width'=>'100','heigth'=>'100'),
				'versions' => array(
				),
			), $conf);
			foreach ($conf['versions'] as $id=>$version) {
				$conf['versions'][$id]=Set::merge(array(
 					         'aspect'=>true,
							 'allow_enlarge'=>false,
		                    ),$version);
			}
			if (is_array($conf['resize'])) {
				if (!isset($conf['resize']['aspect'])) $conf['resize']['aspect']=true;
				if (!isset($conf['resize']['allow_enlarge'])) $conf['resize']['allow_enlarge']=false;
			}
			$fields[$field]=$conf;
		}
		$settings['fields']=$fields;

		$this->settings[$model->name] = $settings;
	}

	/**
	 * Before save method. Called before all saves
	 *
	 * Overriden to transparently manage setting the item position to the end of the list
	 *
	 * @param AppModel $model
	 * @return boolean True to continue, false to abort the save
	 */
	function beforeSave(&$model) {
		extract($this->settings[$model->name]);
		if (empty($model->data[$model->name][$model->primaryKey])) {
		}

		//Ajax でプレアップロードされている場合はそちらを使用する。 modified by M.Araki
		if(isset($model->data[$model->name][TMP_IMG_FILE_NAME])){
			$field = 'image';
			$tempData[$field] = array(
				'tmp_name' => TMP_IMG_DIR_SYSTEM.DS.$model->data[$model->name][TMP_IMG_FILE_NAME],
				'name' => $model->data[$model->name][TMP_IMG_FILE_NAME],
				'type' => $model->data[$model->name][TMP_IMG_FILE_TYPE],
				'error' => '0'
			);
			$model->data[$model->name][$field] = $model->data[$model->name][TMP_IMG_FILE_TYPE];
		}else{
			$tempData = array();
			foreach ($fields as $key=>$value) {
				$field = ife(is_numeric($key), $value, $key);
				if (isset($model->data[$model->name][$field])) {
					if ($this->__isUploadFile($model->data[$model->name][$field])) {
						$tempData[$field] = $model->data[$model->name][$field];
						$model->data[$model->name][$field]=$this->__getContent($model->data[$model->name][$field]);
					} else {
						unset($model->data[$model->name][$field]);
					}
				}
			}
		}

		$this->runtime[$model->name]['beforeSave'] = $tempData;
		return true;
	}

	function afterSave(&$model) {
		extract($this->settings[$model->name]);
		if (empty($model->data[$model->name][$model->primaryKey])) {
		}

		$tempData = $this->runtime[$model->name]['beforeSave'];
		unset($this->runtime[$model->name]['beforeSave']);
		foreach($tempData as $field=>$value) {
			$this->__saveFile($model, $field, $value);
			@unlink($value['tmp_name']);
		}

		return true;
	}


	function afterFind(&$model, &$results, $primary) {
		extract($this->settings[$model->name]);
		$relatedModels = $model->belongsTo;

		if ( is_array( $results ) ) {
			$i=0;
			if (isset($results[0])) {
				while ( isset( $results[$i][$model->name] ) && is_array( $results[$i][$model->name] ) )  {
					foreach ($fields as $field => $fieldParams) {
						if (isset($results[$i][$model->name][$field]) && ($results[$i][$model->name][$field]!='')) {
							$value=$results[$i][$model->name][$field];
							$results[$i][$model->name][$field]=$this->__getParams($model, $field, $value, $fieldParams, $results[$i][$model->name]);
						}
					}
					foreach($relatedModels as $relatedModelName => $param){
						$relatedModel = $model->{$relatedModelName};
						if(!isset($this->settings[$relatedModelName])) continue;
						foreach ($this->settings[$relatedModelName]['fields'] as $field => $fieldParams) {
							if (isset($results[$i][$relatedModelName][$field]) && ($results[$i][$relatedModelName][$field]!='')) {
								$value=$results[$i][$relatedModelName][$field];
								$results[$i][$relatedModelName][$field]=$this->__getParams($relatedModel, $field, $value,$fieldParams, $results[$i][$relatedModelName]);
							}
						}
					}
	                $i++;
				}
			} else {
					foreach ($fields as $field => $fieldParams) {
						if (isset($results[$model->name][$field]) && ($results[$model->name][$field]!='')) {
							$value=$results[$model->name][$field];
							$results[$model->name][$field]=$this->__getParams($model, $field, $value, $fieldParams, $results[$model->name]);
						}
					}
					foreach($relatedModels as $relatedModelName => $param){
						$relatedModel = $model->{$relatedModelName};
						foreach ($this->settings[$relatedModelName]['fields'] as $field => $fieldParams) {
							if (isset($results[$relatedModelName][$field]) && ($results[$relatedModelName][$field]!='')) {
								$value=$results[$relatedModelName][$field];
								$results[$relatedModelName][$field]=$this->__getParams($relatedModel, $field, $value,$fieldParams, $results[$relatedModelName]);
							}
						}
					}

/*				foreach ($fields as $field => $fieldParams) {
					if (isset($results[$model->name][$field]) && ($results[$i][$model->name][$field]!='')) {
						$value=$results[$i][$model->name][$field];
						$results[$model->name][$field]=$this->__getParams($model, $field, $value, $fieldParams, $results[$model->name]);
					}
				}*/
			}
		}
		return $results;
		//return true;
	}

	function __getParams(&$model, $field, $value, $fieldParams, $record) {
		extract($this->settings[$model->name]);
		$result=array();
		if ($value!='') {
			$folderName = $this->__getFolder($model, $record);
			$ext=$this->decodeContent($value);
			$fileName=$field .'.'. $ext;
			$result['path']=$folderName.$fileName;

			$thumb=$fields[$field]['thumbnail'];
			if ($thumb['create']) {
				$result['thumb']=$folderName.$this->__getPrefix($thumb).'_'.$fileName;
			}
			foreach($fields[$field]['versions'] as $version) {
				$result[$this->__getPrefix($version)]=$folderName.$this->__getPrefix($version).'_'.$fileName;
			}
		}
		return $result;
	}

	/**
	 * Before delete method. Called before all deletes
	 *
	 * Will delete the current item from list and update position of all items after one
	 *
	 * @param AppModel $model
	 * @return boolean True to continue, false to abort the delete
	 */
	function beforeDelete(&$model) {
		$this->runtime[$model->name]['ignoreUserAbort'] = ignore_user_abort();
		@ignore_user_abort(true);
		return true;
	}

	function afterDelete(&$model) {
		extract($this->settings[$model->name]);

		foreach ($fields as $field=>$fieldParams) {
			$folderPath=$this->__getFullFolder($model, $field);
			uses ('folder');
			$folder = &new Folder($path = $folderPath, $create = false);
			if ($folder!==false) {
				@$folder->delete($folder->pwd());
			}
		}

		@ignore_user_abort((bool) $this->runtime[$model->name]['ignoreUserAbort']);
		unset($this->runtime[$model->name]['ignoreUserAbort']);
		return true;
	}

	function __isUploadFile($file) {
		if (!isset($file['tmp_name'])) return false;
		return (file_exists($file['tmp_name']) && $file['error']==0);
	}

	function __getContent($file) {
		return $file['type'];
	}
	function decodeContent($content) {
		$contentsMaping=array(
	      "image/gif" => "gif",
	      "image/jpeg" => "jpg",
	      "image/pjpeg" => "jpg",
	      "image/x-png" => "png",
	      "image/jpg" => "jpg",
	      "image/png" => "png",
	      "application/x-shockwave-flash" => "swf",
	      "application/pdf" => "pdf",
	      "application/pgp-signature" => "sig",
	      "application/futuresplash" => "spl",
	      "application/msword" => "doc",
	      "application/postscript" => "ps",
	      "application/x-bittorrent" => "torrent",
	      "application/x-dvi" => "dvi",
	      "application/x-gzip" => "gz",
	      "application/x-ns-proxy-autoconfig" => "pac",
	      "application/x-shockwave-flash" => "swf",
	      "application/x-tgz" => "tar.gz",
	      "application/x-tar" => "tar",
	      "application/zip" => "zip",
	      "audio/mpeg" => "mp3",
	      "audio/x-mpegurl" => "m3u",
	      "audio/x-ms-wma" => "wma",
	      "audio/x-ms-wax" => "wax",
	      "audio/x-wav" => "wav",
	      "image/x-xbitmap" => "xbm",
	      "image/x-xpixmap" => "xpm",
	      "image/x-xwindowdump" => "xwd",
	      "text/css" => "css",
	      "text/html" => "html",
	      "text/javascript" => "js",
	      "text/plain" => "txt",
	      "text/xml" => "xml",
	      "video/mpeg" => "mpeg",
	      "video/quicktime" => "mov",
	      "video/x-msvideo" => "avi",
	      "video/x-ms-asf" => "asf",
	      "video/x-ms-wmv" => "wmv"
		);
		if (isset($contentsMaping[$content]))
			return $contentsMaping[$content];
		else return $content;
	}


	function __saveAs($fileData, $fileName=null, $folder) {

		if (is_writable($folder)) {
			if (is_uploaded_file($_FILES[$fileData]['tmp_name']))
			{
				if (empty($fileName)) $fileName = $_FILES[$fileData]['name'];
				copy($_FILES[$fileData]['tmp_name'], $folder.$fileName);
				return true;
			}
			else
			{
				return false;
			}
		}
		else
		{
			return false;
		}
	}

	function __getFolder(&$model, $record) {
		extract($this->settings[$model->name]);
		return  Inflector::camelize($model->name) .'/'. $record[$model->primaryKey] . '/';
	}
	function __getFullFolder(&$model, $field) {
		extract($this->settings[$model->name]);
		return  WWW_ROOT . IMAGES_URL. Inflector::camelize($model->name) .DS. $model->id .DS;
	}

	function __saveFile(&$model, $field, $fileData) {
		extract($this->settings[$model->name]);
		$folderName = $this->__getFullFolder($model, $field);
		$ext=$this->decodeContent($this->__getContent($fileData));
		$fileName=$field .'.'. $ext;

		uses ('folder');
		uses ('file');
		$folder = &new Folder($path = $folderName, $create = true, $mode = 0777);

		$files=$folder->find($fileName);

		$file= &new File($folder->pwd().DS.$fileName);

		$fileExists=($file!==false);
		if ($fileExists) {
			@$file->delete();
		}

		if (isset($fields[$field]['resize']['width']) && isset($fields[$field]['resize']['height'])) {
			$file=$folder->pwd().DS.'tmp_'.$fileName;
			copy($fileData['tmp_name'], $file);
			$this->__resize($folder->pwd(),'tmp_'.$fileName,$fileName,$field, $fields[$field]['resize']);
			@unlink($file);
		} else {
			$file=$folder->pwd().DS.$fileName;
			copy($fileData['tmp_name'], $file);
		}



		if ($fields[$field]['thumbnail']['create']) {
			$fieldParams=$fields[$field]['thumbnail'];
			$newFile=$this->__getPrefix($fieldParams).'_'.basename($fileName);
			$this->__resize($folder->pwd(),$fileName,$newFile, $field, $fieldParams);
		}
		foreach($fields[$field]['versions'] as $version) {
			$fieldParams=$fields[$field]['thumbnail'];
			$newFile=$this->__getPrefix($version).'_'.basename($fileName);
			$this->__resize($folder->pwd(),$fileName,$newFile,$field, $version);

		}

	}


	function __getPrefix($fieldParams) {
		if (isset($fieldParams['prefix'])) {
			return $fieldParams['prefix'];
		} else {
			return $fieldParams['width'].'x'.$fieldParams['height'];
		}
	}

	/**
	 * Automatically resizes an image and returns formatted IMG tag
	 *
	 * @param string $path Path to the image file, relative to the webroot/img/ directory.
	 * @param integer $width Image of returned image
	 * @param integer $height Height of returned image
	 * @param boolean $aspect Maintain aspect ratio (default: true)
	 * @param array    $htmlAttributes Array of HTML attributes.
	 * @param boolean $return Wheter this method should return a value or output it. This overrides AUTO_OUTPUT.
	 * @return mixed    Either string or echos the value, depends on AUTO_OUTPUT and $return.
	 * @access public
	 */
    function __resize($folder, $originalName, $newName, $field, $fieldParams) {

        $types = array(1 => "gif", "jpeg", "png", "swf", "psd", "wbmp"); // used to determine image type
        $fullpath = $folder;

        $url = $folder.DS.$originalName;

        if (!($size = getimagesize($url)))
            return; // image doesn't exist

		$width=$fieldParams['width'];
		$height=$fieldParams['height'];
        if ($fieldParams['allow_enlarge']===false) { // don't enlarge image
			if (($width>$size[0])||($height>$size[1])) {
				$width=$size[0];
				$height=$size[1];
			}
		} else {
	        if ($fieldParams['aspect']) { // adjust to aspect.
	            if (($size[1]/$height) > ($size[0]/$width))
	                $width = ceil(($size[0]/$size[1]) * $height);
	            else
	                $height = ceil($width / ($size[0]/$size[1]));
	        }
        }

        $cachefile = $fullpath.DS.$newName;  // location on server

        if (file_exists($cachefile)) {
            $csize = getimagesize($cachefile);
            $cached = ($csize[0] == $width && $csize[1] == $height); // image is cached
            if (@filemtime($cachefile) < @filemtime($url)) // check if up to date
                $cached = false;
        } else {
            $cached = false;
        }

        if (!$cached) {
            $resize = ($size&#91;0&#93; > $width || $size[1] > $height) || ($size[0] < $width || $size&#91;1&#93; < $height || ($fieldParams&#91;'allow_enlarge'&#93;===false));
        } else {
            $resize = false;
        }

        if ($resize) {
            $image = call_user_func('imagecreatefrom'.$types&#91;$size&#91;2&#93;&#93;, $url);
            if (function_exists("imagecreatetruecolor") && ($temp = imagecreatetruecolor ($width, $height))) {
                imagecopyresampled ($temp, $image, 0, 0, 0, 0, $width, $height, $size&#91;0&#93;, $size&#91;1&#93;);
              } else {
                $temp = imagecreate ($width, $height);
                imagecopyresized ($temp, $image, 0, 0, 0, 0, $width, $height, $size&#91;0&#93;, $size&#91;1&#93;);
            }
            call_user_func("image".$types&#91;$size&#91;2&#93;&#93;, $temp, $cachefile);
            imagedestroy ($image);
            imagedestroy ($temp);
        }

    }


}
?>


PHPのjson_decodeの挙動がおかしい件

PHPのjson_decode()の挙動がおかしくてはまったので覚書を。
通常、jsonのフォーマットではフィールド名(プロパティ名)部分はクオートする必要はない、というかクオートしないのが正しい形と思っていたが、PHPのjson_decode($json_str)に、クオートされていないフィールド名を持つjsonを渡すと、戻り値はundefinedとなる。
これって仕様としてどうなんでしょうか、、、
ちなみに、 json_last_error()というメソッドがあり、直近のエラーを拾うことができるようなので、おかしいかな?というときは使ってみると何かわかるかも。

設定値や定数はどこに書くか

アプリで外出しにしておきたい設定や、初期設定したい定数などどこに書いておくのがきれいかな?、とよく考えていたのですが、(以前は、config.phpやbootstrap.php, app_controller.php などに書いていたのですが、)、cakephpのグローバルメソッドで

config('file1', 'file2',......);

というのがありました。
このメソッド何をしているかというと、単純に引数で指定した文字列をファイルパスに変換して(/config/file1.php のようになる)、そのパスにファイルがあればinclude_onceしてくれます。また、ファイルが存在しない場合はスルーします。
なので、初期設定したい定数や、場合よって読み込みたい設定などを書いておき、bootstrap.phpでconfig(‘file’);とやってやるといい感じです。

CakePHPでコンソールアプリを作る(その2)

CakePHPでコンソールアプリを作るに引き続き、基本的なメソッドを紹介します。

  • $this->out($str)
  • 標準出力に$strを出力します。

  • $this->in($title, $choice, $default)
  • $choice(配列)で指定した選択リストを表示します。ちょうどbake等の選択肢のようなイメージになります。
    bakeで言うと$this->in(‘Look okay?’, array(‘y’,’n’,’q’), ‘y’); のような感じです。

  • $this->hr($int)
  • “-”を使って区切り線を出力します。$intで数値をしてすると、区切り線の下に指定数分の空白行が入ります。

  • $this->error($title, $msg)
  • $title, $msg を出力してexitします。

  • $this->createFile($path, $content)
  • $path で指定したパスにファイルを作成します

CakePHPでコンソールアプリを作る

PHPでコマンドランの簡単な処理を作ることになったので、せっかくなのでCakePHPのShellを使ってみました。
ブログなどでの取り上げも少ないようなのでちょっと覚書的に書いておこうと思います。
使い方は非常に簡単で、/app/vendors/shells/ に、test.php のような名前でファイルを作ります。
このファイルの中身は、Shellクラスをオーバーライドしたものとします。
例えばこんな感じです。

<?php
class TestShell extends Shell{
	private $_str = array(
			'construct' => 'コンストラクト',
			'initialize' => '初期化処理',
			'startup' => '開始処理',
			'main' => '基本処理',
			'choise' => '選択してください',
			'suspend' => '中止されました',
			'openFile' => 'ファイルを開いて表示します。パスを入力してください。:'
		);

	function initialize(){
		mb_convert_variables('SJIS', 'UTF-8', $this->_str);
		$this->out($this->_str['initialize']);
	}
	function startup(){
		$this->out($this->_str['startup']);
	}
	function main(){
		if($this->in($this->_str['choise'], array('y','q'), 'y') == 'q'){
			$this->error('line:'.__LINE__.' on '.__FILE__, $this->_str['suspend']);
		}else{
			$this->hr(1);
			$this->out($this->_str['main']);
			$this->hr(1);
			$input = $this->in($this->_str['openFile']);
			echo file_get_contents($input);
		}
	}
}
?>

コマンドラインからのアクセスには、

cake シェルのクラス名 メソッド名 引数1 引数2,,,,

のようになります。メソッド名を省略すると、mainメソッドが呼ばれます。
一番最初の cake は /cake/console/ 配下にあるコマンドなので、あらかじめ /cake/console を環境変数に入れておいた方が使いやすいでしょう。
その上で、APPのディレクトリに移動して上記のようにコマンドをたたきます。
また、別の方法として

cake -app APPへのパス シェルのクラス名 メソッド名 引数1 引数2,,,,

のように明示的に指定すると、どこからでもアクセスできます。

Shellクラスにはコンポーネントと同様に、startup, initialize 等のコールバックメソッドが用意されていますので、初期化処理や定型処理を書いておくのもいいかもしれません。
また、コントローラと同様に、$uses メンバ変数で使用するモデルを指定できるので、コントローラで行う処理と同じ感覚でモデルのデータにアクセスできます。

Windowsのコマンドラインから使用する場合、文字コードがSJISになるので、今回は上記のように、メンバ変数に使用するメッセージ文言を定義しましたが、CakePHPのLocale機能を使って、

$this->in(__get('openFile'));

のようにするとより綺麗かも知れません。

JavaScriptデバッグツールJSDT

最近Eclipseでのデバッグがマイブームで、何かJSのデバッグができるプラグインはないかと探していたら、JSDTというのを見つけました。
実際普段のデバッグではFirebugのステップ実行で十分なのですが、Eclipseでステップ実行とかしたら気持ちいいかと思い、、、。
まずは、上述サイトのアップデートサイトURLを使ってインストール。
http://jsdt.googlecode.com/svn/trunk/org.ayound.js.debug.update
次に、Eclipseの実行>デバッグの構成、でJavascriptDebugを選択し、左上の新規作成アイコンをクリックして新規構成を作ります。
JSDTのデバッグでは、JSDTがプロキシサーバーの役割を果たすようで、URLはhttpから始まる絶対パスを記述します。
ポートはデフォルトの8088をそのまま使用。ブラウザーの欄に適宜ブラウザパスを設定します。
これでデバッグボタンをクリックすると、先程設定したブラウザでURLが開かれ、デバッグが開始されます。
パースペクティブをJSDTにしてブレークポイントを張れば止まるのでしょう。(未確認)
ですが、どうもいまひとつ使い方が判りません。
文字コードを設定し挙げても日本語(UTF-8)のページが文字化けするようです。
実行すると外部サーバーのJSファイルも含め、全てのJSを開いてしまうのも不便です。
外部のものをリモートデバッグできるのはある意味便利かもしれないのですが、、、
もう少し使ってみようかとも思うのですが、Firebugで十分かな、、、

PDT2.0+XDebugでリモートデバッグ(その2)

PDT2.0+Xdebugでデバッグに引き続いて、Eclipseの設定です。
以下、日本語化したメニュー項目で記載します。
まずは、Eclipseの、設定 > PHP で、PHPサーバーPHP実行可能ファイル、の2項目を適宜設定します。この時、PHPデバッガーの項目で、XDebugを選択します。
次に、設定 > PHP > デバッグの、PHPデバッガー欄でXDebugを選択します。
これでデバッガの設定ができました。最後に実際のデバッガ構成の設定です。
Eclipseメニューの、設定 > 実行 > デバッグの構成、をクリックしてデバッグ構成ダイアログを表示します。
ここで、左のメニューで、PHP Webページを選択し左上の「新規の起動構成」をクリックして新規構成を選択します。

  • サーバー・デバッガー:XDebug
  • PHPサーバー:先程設定したサーバー

を選択します。

デバッグ構成

デバッグ構成

「ファイル」の欄は実行ファイルを直接指定できますが、今回はCakePHPでのデバッグをしますので、アプリのルートとなるURLとして「/」を入力しました。ブラウザでアクセスできるURL形式で指定します。
ここで、「ファイルが存在しません」と×マークが出ますが、気にしなくてOKです。
また、CakePHPのようなフレームワークの場合、「最初の行でブレーク」はチェックをはずした方がよいでしょう。(でないと自分設定したブレークポイントに行き着くまでにかなりのステップが必要になります)
あとは、Eclipseのカブトムシアイコンから先程作った設定を選択して実行すれば、設定したブレークポイントでとまってくれます。
終了ボタンをクリックするまではデバッグモードが続いていますので、画面遷移やフォーム送信など行って、実際の処理の中でステップ実行ができます。
今まで、fireCakeやfirePHPを使って変数のチェックなどをしていましたが、格段にやりやすくなった気がします。
また、ステップインしていくことでコアライブラリの中で何が行われているのかを見ることもできるので、コアライブラリの挙動の理解にもつながった気がします。

PDT2.0+XDebugでリモートデバッグ(その1)

PDT2.0+Xdebugでデバッグ環境を構築してみようと思います。
思い立ったきっかけは、普段使っているCakePHPでのデバッグに役立てたいためです。
今回は

  • Windows-7 64bit
  • Eclipse3.4
  • PDT2.0
  • Apache2.0.63
  • PHP5.2.9-2

という環境がすでに整っているところから始めます。

まずは、Xdebugのダウンロードページからバージョンにあったものをダウンロードします。
最適なバージョンがわからない場合、実行環境のサーバー上でphpinfo();を実行し、そのHTMLソースをインストラクションのページのテキストボックス貼り付けて、Analyse my phpinfo() output をクリックすると、最適なバイナリバージョンが提示されます。
なお、今回OSはWindows7の64bitですが、PHP自体は32bit用(5.2.9までは64bit版はない?)がインストールされているので、ここでも32bit用のバイナリを選択しました。
※今回、上記のインストラクションのページでXdebug 2.1.0rc1 が提示されたのですが、これをインストールしてみると変数が表示されないという問題があり、最終的に2.0.4を使うことになりました。こちら詳細が記載されているようです。(PDT2.0のバグのようです)

つづいて、php.iniの設定
以下をphp.iniに追記ましす。

[xdebug]
zend_extension_ts="C:\PHP\ext\php_xdebug-2.0.3-5.2.5.dll"
xdebug.remote_enable=1
xdebug.remote_handler="dbgp"
xdebug.remote_mode=req
xdebug.remote_host="localhost"
xdebug.remote_port=9000
xdebug.remote_log="C:\Program Files (x86)\Apache Group\Apache2\logs\xdebug.log"
xdebug.manual_url = "http://jp2.php.net"
;xdebug.collect_params = On
;xdebug.dump.GET = *
;xdebug.dump.POST = *

これでデバッグの準備ができました。
Eclipseの設定・実行手順いついては次回に書きたいと思います。

getting health insurance in new york buy clomid online UK major health insurance companies buy levitra uk online what are wells fargo hours buy finasteride affordable health insurance for children accutane no prescription medical center of trinity viagra online uten resept midwestern university wellness center dapoxetine top individual health insurance companies viagra ireland