Category Archives: PHP

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'));

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

debugKitToolbarが激しく便利

CakePHPのデバッグ用プラグインのdebugKitToolbarが激しく便利です。
今まではFireCakeやFirePHPを使っていて、それなりに重宝していたのですが、先日のカンファレンスで小耳に挟み、早速使ってみました。
まずは、http://www.ohloh.net/p/cakephp-debugkit/ からダウンロードして、解凍してできたdebug_kitを /app/plugins/におきます。で終了。
後はapp_controller.php等で読み込んであげればOK。

var $components = array('DebugKit.Toolbar');

こんな感じ。
ただ、デフォルトでは debugが1以上だと無条件に動作するので、モバイルのテストなどする時は気をつけたほうがいいかも。
バイト数制限を簡単に超えてしまいテストすらできません。

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の設定・実行手順いついては次回に書きたいと思います。

Eclipse上でXdebugによるデバッグ

Eclipse上でXdebugによるデバッグ環境を整えたのですが、かなりてこずったので備忘録的に。
実際のインストール・設定はのちほど書こうと思います。
で、どこではまったかというと、今回2台の端末でそれぞれ同じ環境構築をしたのですが、なぜか1台だけでeclipseのデバッグボタンを押しても、うんともすんともいいません。で、eclipseのログ(ワークスペース配下の.metadata/.log)を見てみたのですが、なんのこっちゃ的な内容でわかりません。次にApacheのerror.logを見たのですがこちらは何もありません。今度はwindowsのシステムログを見てみたりしたのですがこちらもそれらしいものはありません。
で、xdebug.log(php.iniで設定)を見てみると、ファイルが出力されているのでデバッグは実行されているのかな?
そこで、デバッグ用のポートがふさがっているのでは?と考え、コマンドプロンプトで netstat -ano を叩いてみると、正常にデバッグできる端末と比較して違いが。
正常な方は9000,9980,10000のポートを同じPIDが使用しているのですが、デバッグできない方は10000だけ他のPIDに割り振られています。
(9000はXdebug、10000はzendDebuggerが使用するポートです。9980はは不明)
そもそも、このPIDはなんぞや、を調べるために、コマンドプロンプトで tasklistを叩いてみます。(tasklistはタスク一覧を表示するコマンドのようです。)9000,9980 はEclipseが使っていたのですが、10000をAgentsvc.exeというプロセスが使用している模様。
Agentsvc.exeって何?と思いググって見ると、どうやらMSOfficeのイルカ君らしい。なんじゃそりゃ、、、。で早速タスクマネージャでこのサービスを終了させてEclipseを起動するとめでたくリモートデバッグが実行されました。感動的、、、
でも、ブレークポイントでとまっているのですが変数が表示されません、、、、何で?
Read more »

phpでssiを使う設定

最近phpでssiを使うことがあったのだが、httpd.confの書き方で挙動が違うことを経験したので覚書。
通常、SSIを通場合、AddType text/html .shtml などと書くが、この記述がPHPのAddTypeより後に書かれているとPHPとして実行されない(PHPコードがそのまま出力される)ということがおきるようです。ちょっと悩んだ結果試しに記述位置を入れ替えてみたら、SSI、PHPともに実行されたので一旦OK。
どうしてそうなるのか、細かく調べたいところだけど、一旦OKとしましょう(汗)

AddType text/html .shtml .html .php
AddOutputFilter INCLUDES .shtml .html .php

AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
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