月別アーカイブ: 2012年6月

[PHP]画像のリサイズ・トリミング(Zebra_Image.php編)

さて、前回に引き続き画像のリサイズ(拡大縮小)し、トリミング(切り出し)についてです。
今回は「Zebra_Image.php」を利用します。

前回同様、今回もアップロードしたファイルを100px×100pxの正方形に中央を基準にトリミングします。

下記ソースの流れはこんな感じです。
1.アップロードしたファイルをリネーム
2.既定フォルダに保存
3.ファイルの縮小・トリミング

<?php
require_once 'Zebra_Image.php';
define('IMAGE_AREA_LENGTH', 100);    //画像(正方形)の1辺の長さ
$upload_path = $_SERVER['DOCUMENT_ROOT'].'/upload/';
if(!is_uploaded_file($_FILES['toProcess']['tmp_name'])){
die('アップロードエラー');
}
//アップロード成功
$tmp_name = $_FILES['toProcess']['tmp_name'];    //元画像ファイル
//ファイル名を取得
$file_name = date('YmdHis');    //YYYYMMDDHHIISSで名前を付ける
$file_name = uniqid($file_name.'_');    //重複しない名前
//拡張子を取得
$wrk = explode('.', $_FILES['toProcess']['name']);
$extension = array_pop($wrk);
//画像保存パス
$output_file = $upload_path.$file_name.'.'.$extension;
//画像を移動
move_uploaded_file($tmp_name, $output_file);
//画像変換
$image = new Zebra_Image();
$image->source_path = $output_file;    //元ファイル
$image->target_path = $output_file;    //書き出しファイル
//リサイズ・トリミング
if (!$image->resize(IMAGE_AREA_LENGTH, IMAGE_AREA_LENGTH, ZEBRA_IMAGE_CROP_CENTER)) {
//エラー発生時
switch ($image->error) {
case 1:
echo 'ファイルが存在しません';
break;
case 2:
echo 'ファイルを読み込めません';
break;
case 3:
echo '変換ファイルを書き出せません';
break;
case 4:
echo 'サポートされてないファイル形式です';
break;
case 5:
echo '変換ファイルはサポートされていない形式です';
break;
case 6:
echo 'GDが書き出しファイルの形式をサポートしてません';
break;
case 7:
echo 'GDがインストールされてません';
break;
}
}

「class.image.php」はリサイズとトリミングを分けて行いましたが
「Zebra_Image.php」はこれを一気に行うことができ、トリミングの中央指定も簡単です。

※ご注意
掲載している内容についてはご自身の責任で参考にされてください。

[PHP]画像のリサイズ・トリミング(class.image.php編)

アップロードした画像ファイルをリサイズ(拡大縮小)し、トリミング(切り出し)を行いたいとき、「class.image.php」を使用する方法があります。

今回は、アップロードしたファイルを100px×100pxの正方形に中央を基準にトリミングします。

下記ソースの流れはこんな感じです。
1.アップロードしたファイルをリネーム
2.既定フォルダに保存
3.ファイルの縮小
4.ファイルのトリミング

<?php
require_once 'class.image.php';
define('IMAGE_AREA_LENGTH', 100);    //画像(正方形)の1辺の長さ
$upload_path = $_SERVER['DOCUMENT_ROOT'].'/upload/';
if(!is_uploaded_file($_FILES['toProcess']['tmp_name'])){
die('アップロードエラー');
}
//アップロード成功
$tmp_name = $_FILES['toProcess']['tmp_name'];    //元画像ファイル
//ファイル名を取得
$file_name = date('YmdHis');    //YYYYMMDDHHIISSで名前を付ける
$file_name = uniqid($file_name.'_');    //重複しない名前
//拡張子を取得
$wrk = explode('.', $_FILES['toProcess']['name']);
$extension = array_pop($wrk);
//画像保存パス
$output_file = $upload_path.$file_name.'.'.$extension;
//画像を移動
move_uploaded_file($tmp_name, $output_file);
//リサイズ    (縦横の最大サイズを100ピクセル)
$size = GetImageSize($output_file);    //元画像サイズ取得
if($size[0] > $size[1]){
$height = IMAGE_AREA_LENGTH;
$width = $height * ($size[0] / $size[1]);
}else{
$width = IMAGE_AREA_LENGTH;
$height = $width * ($size[1] / $size[0]);
}
//画像オブジェクト生成
$thumb = new Image($output_file);
//リサイズ
$thumb->width($width);
$thumb->height($height);
$thumb->save();
//トリミング
$thumb->width(IMAGE_AREA_LENGTH);
$thumb->height(IMAGE_AREA_LENGTH);
if($width < $height){
$thumb->crop(0, ($height - $width) / 2);
}else{
$thumb->crop(($width - $height) / 2, 0);
}
$thumb->save();

「class.image.php」はリサイズとトリミングを分けて行うことによって動作させることができました。

ちょっとごちゃごちゃした感じになってしまいました。
他にも「Zebra_Image」を使うと少しコードがすっきりします。
それはまた次回に・・・。

※ご注意
掲載している内容についてはご自身の責任で参考にされてください。

[HTML]さくらのブログでSyntaxHighlighterを使う場合の留意点

このブログではプログラムソースの表示に「SyntaxHighlighter」を使用しています。
しばらく使っていて色々分かったところもあるので、一度ここで確認をしておこうと思う。

○編集
preタグの中にHTML上影響の与える文字が含まれると、うまく表示されない場合があるので置き換え文字を使用する。
このサイトが便利。

「preタグ・メーカー」
http://www.mapee.jp/tools/pretagmaker/

○投稿
改行HTMLタグ変換
「改行をタグに変換しない 」に設定
URL補完
「補完しない」 に設定

○初期設定
1.SyntaxHighlighterを自分が所有するサーバスペースにアップ

2.HTMLの編集
管理パネル
「デザイン」→「HTML」→「HTMLの追加」

ここで、必要なタグの追加
※headタグ中

<!-- SyntaxHighlighter -->
<link type="text/css" rel="stylesheet" href="http://<自分が所有するサイトのドメイン>/syntaxhighlighter/styles/shCore.css">
<link type="text/css" rel="stylesheet" href="http://<自分が所有するサイトのドメイン>/syntaxhighlighter/styles/shThemeDefault.css">

※bodyの閉じタグの手前

<!-- SyntaxHighlighter -->
<script type="text/javascript" src="http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shCore.js"></script>
<script type="text/javascript" src="http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shAutoloader.js"></script>
<script type="text/javascript">
SyntaxHighlighter.autoloader(
'applescript            http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushAppleScript.js',
'actionscript3 as3      http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushAS3.js',
'bash shell             http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushBash.js',
'coldfusion cf          http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushColdFusion.js',
'cpp c                  http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushCpp.js',
'c# c-sharp csharp      http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushCSharp.js',
'css                    http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushCss.js',
'delphi pascal          http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushDelphi.js',
'diff patch pas         http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushDiff.js',
'erl erlang             http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushErlang.js',
'groovy                 http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushGroovy.js',
'java                   http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushJava.js',
'jfx javafx             http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushJavaFX.js',
'js jscript javascript  http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushJScript.js',
'perl pl                http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushPerl.js',
'php                    http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushPhp.js',
'text plain             http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushPlain.js',
'py python              http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushPython.js',
'ruby rails ror rb      http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushRuby.js',
'sass scss              http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushSass.js',
'scala                  http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushScala.js',
'sql                    http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushSql.js',
'vb vbnet               http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushVb.js',
'xml xhtml xslt html    http://<自分が所有するサイトのドメイン>/syntaxhighlighter/scripts/shBrushXml.js'
);
SyntaxHighlighter.defaults['toolbar'] = true;
SyntaxHighlighter.config.bloggerMode = true;
SyntaxHighlighter.all();
</script>
※ご注意
掲載している内容についてはご自身の責任で参考にされてください。

[HTML]特定のブラウザで画面が真っ白に表示される

特定のブラウザで画面が真っ白になる場合があります。

ソースを表示させると、きちんとHTML自体はブラウザにダウンロードされている。
ブラウザのエンコードも問題ないし、ファイル自体の文字コードも合っている。
現象が確認できるブラウザでは再現率100%。
開発していたブラウザではちゃんと表示されていたのに、どうして?

そんな問い合わせが時々あります。

こういった場合は「文字化け」を疑います。
例えば次のソースを見てみてください。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<title>タイトル</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
・・・以下略

一見すると正しい記述に見えますが、この記述だとmetaタグで「utf-8」が
指定される前にtitleタグ内のマルチバイト文字「タイトル」が現れます。

ブラウザがエンコードを認識する前にマルチバイト文字を読みこみ
一部のブラウザではタイトルの時点で文字化けが発生する場合があります。
結果としてブラウザには白い画面しか表示されなくなります。

解決策としてはタグの順番を入れ替えればOKです。

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>タイトル</title>
・・・以下略

titleタグに限らず、日本語(マルチバイト文字)が出力される前に
必ずエンコードを指定しておけば良いでしょう。

しかしながら、修正したファイルを本番サーバにアップしたときに
即時反映されない場合があります。

典型的ですが、こういった場合はサーバやクライアント側のキャッシュである可能性が考えられます。
クライアント側のキャッシュをクリアし、許されるならサーバキャッシュの削除、もしくは再アップロードで動作する場合があります。

いずれにしてもWebで開発する以上は、宿命的にブラウザ対応(主に文字化け)との戦いをしていくことになります。

仕様を統一してくれないかな、というのは世界中のWeb系エンジニアの願いです。。。

※ご注意
掲載している内容についてはご自身の責任で参考にされてください。

[PHP]googleanalytics.class.phpは10個しかメトリクスを指定できない

さて、Google Analytics APIのクラスライブラリとしてgoogleanalytics.class.phpがあります。

まとめてデータを取得できるところが非常に便利なのですが
データ取得時に下記のようなエラーメッセージが出ることがあります。

エラーメッセージ
「Error: Bad request – Requested 11 metrics; only 10 are allowed.」

なんと、取得するときにメトリクスは10個までしか受け付けてもらえません。
たくさんコンバージョン(目的)の設定をしている場合は注意が必要です。

エラーが起こる記述

require_once 'googleanalytics.class.php';
$ga_id = 'AAA';	//Google Analytics ID
$ga_pass = 'BBB';	//Google Analytics パスワード
$ga_profile_id = 'ga:XXXXXXXX';	//プロファイルID
$metrics = '';
$metrics .= 'ga:visitors,';
$metrics .= 'ga:exits,';
$metrics .= 'ga:goal1Completions,';
$metrics .= 'ga:goal2Completions,';
$metrics .= 'ga:goal3Completions,';
$metrics .= 'ga:goal4Completions,';
$metrics .= 'ga:goal5Completions,';
$metrics .= 'ga:goal6Completions,';
$metrics .= 'ga:goal7Completions,';
$metrics .= 'ga:goal8Completions,';
$metrics .= 'ga:goalCompletionsAll';
try{
$ga = new GoogleAnalytics($ga_id , $ga_pass);
$ga->setProfile($ga_profile_id);
$ga->setDateRange('2012-06-01' , '2012-06-30');
$report = $ga->getReport(
array(
'dimensions' => urlencode('ga:date'),
'metrics'    => urlencode($metrics),
'sort'       => 'ga:date'
)
);
print_r($report);
} catch (Exception $e) {
print 'Error: ' . $e->getMessage();
}

とは言え、必要なデータはやはり取らないといけません。
こうなったら2回getReportを投げて戻り値の配列をマージしてみます。

require_once 'googleanalytics.class.php';
$$ga_id = '<Google Analytics ID>';
$ga_pass = '<Google Analytics パスワード>';
$ga_profile_id = 'ga:XXXXXXXX';	//プロファイルID
$metrics = '';
$metrics .= 'ga:visitors,';
$metrics .= 'ga:exits,';
$metrics .= 'ga:goal1Completions,';
$metrics .= 'ga:goal2Completions,';
$metrics .= 'ga:goal3Completions,';
$metrics .= 'ga:goal4Completions,';
$metrics .= 'ga:goal5Completions,';
$metrics .= 'ga:goal6Completions,';
$metrics .= 'ga:goal7Completions,';
$metrics .= 'ga:goal8Completions,';
$metrics .= 'ga:goalCompletionsAll';
try{
$ga = new GoogleAnalytics($ga_id , $ga_pass);
$ga->setProfile($ga_profile_id);
$ga->setDateRange('2012-06-01' , '2012-06-30');
$metrics_arr = explode(',', $metrics);	//メトリクスを配列化
$step_total = ceil(count($metrics_arr) / 10);
for($step = 0; $step < $step_total; $step++){
//10個ずつmetricsを抽出
$report_metrics = implode(',', array_slice($metrics_arr, $step * 10, 10));
$report_wrk = $ga->getReport(
array(
'dimensions' => urlencode('ga:date'),
'metrics'    => urlencode($report_metrics),
'sort'       => 'ga:date'
)
);
//初回は代入のみ
if($step == 0){
$report = $report_wrk;
continue;
}
//2回目移行は配列をマージ
foreach ($report_wrk as $wrk_idx => $ga_ret) {
$report[$wrk_idx] = array_merge($report[$wrk_idx], $report_wrk[$wrk_idx]);
}
}
print_r($report);
} catch (Exception $e) {
print 'Error: ' . $e->getMessage();
}

なんだか、カッコ悪い感じもしますが、GoogleAnalyticsのオブジェクト化を
1回だけにしておくのがポイントです。
このオブジェクトを作成するだけで僕の環境では2~3秒かかってました;

※ご注意
掲載している内容についてはご自身の責任で参考にされてください。

[PHP]バッチ処理 後編[バッチファイル作成&設置]

さて、バッチ開発後編です。
まずは、ファイルの絶対パスを一応確認しましょう。
PHPファイルを作成し、batchディレクトリにアップロードします。
batch_test.php 新規作成

print(__FILE__).PHP_EOL;

次に、TeraTermとかでバッチを置くディレクトリに移動
cd batch
実行
php batch_test.php
実行結果
/var/www/vhosts/<ドメイン名>/batch/batch_test.php
これが今回製作したバッチファイルの絶対パスになります。
次にbatch_test.phpを書き換えます。
適当なテーブル(t_batch_test)を一個DBに作成し、
INSERTするようにします。
batch_test.php 書き換え

$host = '<ホスト名>';
$user = '';
$pass = '';
$dbname = '';
try {
$dbh = new PDO('mysql:host='.$host.';dbname='.$dbname, $user, $pass);
$sql = "insert into t_batch_test (test) values ('from batch')";
$stmt = $dbh->prepare($sql);
$flag = $stmt->execute();
if ($flag){
print('success').PHP_EOL;
}else{
print('failed').PHP_EOL;
}
$dbh = null;
} catch (PDOException $e) {
print($e->getMessage());
die('error!!!').PHP_EOL;
}

再度、アップロードしてファイルを上書きした後
コマンドから実行
実行
php batch_test.php
表示結果で「success」と出れば、PHPの記述は問題ありません。
次はcronの設定です。
cronについて僕はレンタルサーバの業者から提供されている
管理者パネルで設定しましたが、そういうツールがない場合は
viあたりのエディタでcron設定ファイルを編集できます。
詳細な設定方法についてはここでは割愛します。
設定時にコマンドを下記のように設定します
コマンド
php /var/www/vhosts/<ドメイン名>/batch/batch_test.php
cronで指定した時刻に追加がされていれば完了です。
実行方法は他にPHPのsystem関数を使う手もあります。

※ご注意
掲載している内容についてはご自身の責任で参考にされてください。

[PHP]バッチ処理 前編[設置ディレクトリの準備]

windowsのシステムでバッチ処理をする場合、batファイルや
VBなんかで作ったexeなどをタスクマネージャみたいな
スケジューラでキックするのは常套手段だと思う。
じゃあ、linuxでPHPやらが動いている環境がある場合
どういう方法があるのかということでチャレンジしてみた。
今回は手持ちのレンタルLinuxサーバでバッチ処理をする方法を考える。
言語はPHPで、このPHPを起動するのはcron(クーロン)を使う。
なぜPHPかというと、既にWEBアプリで既に作った部品を流用できるから。
特にDBまわりのモジュールをもう一回Javaとかで作る気にならなかった。。。
cronはwindowsで言うところのタスクマネージャみたいなもの。
サーバ側で提供されていたコントロールパネルから設定できた。
対応しているかはレンタルサーバの会社とサービス内容にもよる。
バッチの場所は僕のサーバの環境では特に用意されていなかったので
ルートの(httpdocsと同じ)階層に新しくディレクトリを作成して
パーミッションを700で設定した。
※httpのルートに置くとブラウザでアクセスされる危険性があるので、もちろんやらない。
○手順
・httpdocsと同じ階層にいるか確認
・バッチ用ディレクトリ作成
 mkdir <ディレクトリ名>
 mkdir batch
・パーミッション変更
 chmod <属性値> <ディレクトリ名>
 chmod 700 batch
・所有者とアクセス権を確認
 ls -l
 表示結果:
 drwx—— 2 root root 4096 Jun 25 14:11 batch
アップロードを考慮してユーザ名(左から一番最初のrootの位置)がftpのユーザと
違った場合はユーザ名を合わせる。
・所有者の変更
 chown <ユーザ名> batch
次回はバッチファイル作成と設置です。

※注意
掲載している内容についてはご自身の責任で参考にされてください。

[FFFTP]mkdirで作ったディレクトリにアクセスできない

FFFTPを使ってコンテンツをアップロードする際に
「no such file or directory」となる。
と、こんな問い合わせがあった。
こういった場合、権限の問題を考える必要がある。
要は、このディレクトリを誰が作ったか、どんな人にアクセスを許しているか
ということ。
よくあるのが、TeraTermみたいなターミナルエミュレーターでログイン後、
suコマンドからroot権限でディレクトリを作って、そこにFFFTPでアクセスする場合。
その時は、ディレクトリの所有者とFFFTPでつなぐユーザ名を合わせる必要がある。
○所有者とアクセス権を確認
ls -l
○所有者の変更
chown <ユーザ名> <ディレクトリ名>
とりあえず、解決。

※注意
ご自身の責任でご参考にされてください。
ところどころ端折っているので、コマンドの実行にはリファレンス等を確認してください。

[XAMPP]php.iniでextensionを有効にしても反映されない場合の意外な可能性

ある学生からXAMPPでPHPを使ってて下記エラーがどうしても消えないと
いうことで質問をされました。
Fatal error: Call to undefined function curl_init()
まず、php.iniファイルの下記項目のコメント「;」を外して上書き
extension=php_curl.dll
その後、apacheを再起動するように指示しました。
瞬殺だろうと思ったのですが、うまくいかないらしいです。
おかしいなと思って、libeay32.dll、ssleay32.dll
の存在確認や環境変数Pathが通っているかも確認するも
すべて正常。。。
おかしいなと思っていたのですが、ふと
phpinfo()を使ってConfiguration File (php.ini) Path を確認
してもらって、納得しました。
phpinfoには「xampp\apache\bin」がphp.iniのパスとして
表示されてましたが、彼はこれまで「xampp\php」にあるphp.iniを
編集していたらしいです。
ああ、なるほどねぇ。。。
結構ひっかかる人いるかもね、これ。

[XAMPP]Apacheが停止、再起動できない

掲題の件で困っている人がいたので確認してみました。
とりあえず、XAMPPコントロールパネルを一度終了したのち
「管理者として実行」から起動すると動きました。
XPにどっぷりだとVistaや7で、こんな問題にぶちあたったりしますね。。。