カテゴリー「php」の11件の記事

2014.10.05

気象統計情報

お医者様から、めまいやふらつき、突発性難聴など、内耳が関連している病気(症状?)は、気圧変動に関係していると聞きました。

じゃあ、酷いめまいがあった前後の気圧はどうなってたんだろう?と気になったので、気象庁のWEBサイトで確認してみたのですが、、、なんか使いにくいです(すみません個人の感想・・・)。

続きを読む "気象統計情報" »

2012.03.02

ワレキでググってビビった件

これまた暇つぶし目的で、特に意味なく暇に任せて好きなだけ和暦の日付でウェブ検索(Google利用)できるサイトを作ってみたのだが、「平成24年03月02日」といった形式の日付でググると、気象庁の地震情報がトップにたくさん上がってきて、なるほどそういうこともあるもんかいなと、ちょっと関心。

で、昨年の3月11日以前の数日とかを検索してみると、ひっきりなしに地震が発生していたようなんですが、最近もかなり頻発しているように思えてちょっと怖い。

日々是検索-とにかく和暦で検索してみようってコンセプト

こんなつもりで作ったわけではないのですが・・・

2012.02.28

[php] PHPExcelで幅と高さを指定して画像を貼り付ける

帳票出力にPHPExcelを使っているのですが、本日、画像の縮尺変更で少しはまったのでメモしておきます。

画像の幅と高さをsetWidth()とsetHeight()で自由に変更して(アスペクト比を無視して)シートに貼るときは、先にsetResizeProportional(false)で、縦横比を保持しないように設定しましょう。ってことなんです。ソース読んでわかりました。

↓の例。たとえば images/hoge.png が640x480pxの画像だとして、これを 50x50 に縮小してエクセルに貼り付けたい場合、単純に以下のようにやってもうまくいきません。画像オブジェクトがデフォルトで元画像の縦横比を保持するようになっているため、あとから呼び出しているsetHeightで幅も設定されてしまうためです。

$d = new PHPExcel_Worksheet_Drawing();
$d->setPath('images/hoge.png');
$d->setWidth(50);
$d->setHeight(50);
$d->setWorksheet(
    $excel->getActiveSheet());

望み通りの結果を得るには、以下のように先に setResizeProportional(false) と呼び出して縦横比を保持しないように設定する必要があるんですね。

$d = new PHPExcel_Worksheet_Drawing();
$d->setPath('images/hoge.png');
//↓これが必要
$d->setResizeProportional(false);
//↑これが必要
$d->setWidth(50);
$d->setHeight(50);
$d->setWorksheet(
    $excel->getActiveSheet());

ちなみに、PHPExcel_Worksheet_Drawing(正確には基本クラスのPHPExcel_Worksheet_BaseDrawing)には、 setWidthAndHeight というメソッドがありますけど、これは縦横比を保持する設定でしか動作しません。指定した幅と高さにうまく収まるような大きさに縦横比を保持したまま収めるためのメソッドのようですな。縦横比を保持しないようにしていると、見事に何にもしないで帰ってきますw

PHPExcelはソースを読むと妙な面白さがあって不思議と腹が立たない。とても良いことですね。

2012.02.24

[php] 日付演算 DateTime/DateIntervalのうるう年対応

仕事で関わっているシステムで、日付の演算(一日あととか一ヶ月前など)でDateTimeクラスとDateIntervalクラスを使っていたのですけど、うるう年に対応していなくて声を上げて驚いた。

2012年3月1日の前日を取得するコード。

$d = new DateTime();
$d->setDate(2012,3,1);
$d->sub(new DateInterval('P1D'));
$t = $d->getTimestamp();
echo date('Y-m-d', $t);

出力結果はまさかの2012-02-28。これはいろいろな局面でまずいでしょ。見間違いかと何度かやってみたがダメ。

仕方が無いので別なやり方。以下のような記述が出来ることを発見して事なきを得た。この「演算内容を文字列として書く」というところがイヤなんだけど、まー仕方がない。このほうが短くなるし。

$t = strtotime("2012-03-01 -1 days");
echo date('Y-m-d', $t);
//出力結果  2012-02-29

しかし、こんな単純なバグがあるもんか?と自宅でやってみたら正しい結果。バージョン違いかな。ちなみにホスティングしているサーバーでは、DateTimeが使えなかった(笑)。

いろいろ勘案すると、DateTime/DateIntervalは使わないほうがよいのかな。ちょっとイカレタ仕様だし(笑) ― 特にDateIntervalのコンストラクタとか目を疑うしw

2012.02.15

Twitterアプリを試作してみた

今日は風邪ひいて仕事を休んだ。昨日の朝から感じていた喉周辺の痛みが悪化。昨夜は酒を控えてみたが効果が無かったようである。飲めばよかったね。

喉は痛いが熱は出ず、寝込むわけでも無い。夕方くらいから頭脳明晰(でもないか)で少々退屈。なのでPC立ち上げてなにしよう・・・と考え、「あ、せやせや長い間放置していたTwitterアプリに手をつけてみよう!」ということになった。1年ほど前かな?「OAuth認証ってなんじゃらほい?」とコチョコチョしていたものなんだけど、当時は結局、認証を通せず「わけわからんわー」と放置していたもの。でも今日は軽く認証を通せて、タイムラインも見えて、つぶやけた。めでたい。

アプリケーションとしてはまったく形にはなっていませんし何をするにも不便この上ないブツなので公開はしませんが、自作のなんちゃってPHPフレームワークのなんちゃってアクションクラスの中身だけここに貼っておきましょう。いろいろ創造をたくましくしてくださいな。

<?php
/**
 * インクルードパスを追加
 */
function add_include_path($path) {
	ini_set(
		'include_path',
		ini_get('include_path') .
		PATH_SEPARATOR .
		$path);
}
add_include_path('sys/ext/Net_URL2-2.0.0');
add_include_path('sys/ext/HTTP_Request2-2.0.0');
add_include_path('sys/ext/HTTP_OAuth-0.2.3');
add_include_path('sys/ext/Services_Twitter-0.6.3');

require_once('HTTP/OAuth.php');
require_once('HTTP/OAuth/Consumer.php');
require_once('Services/Twitter.php');
require_once('conf/twitter.conf');

class Actions {
	public $is_oauth = false;
	
	/**
	 * コンストラクタ
	 */
	public function Actions() {
		$this->is_oauth = $this->isOAuth();
		if($this->is_oauth) {
			$this->access_token =
				$_SESSION['access_token'];
			$this->access_token_secret =
				$_SESSION['access_token_secret'];
		}
	}
	
	/**
	 * トップページのアクション。
	 * アプリ認証のURLを表示する
	 */
	public function execute_index($request) {
		$consumer = $this->getConsumer();
		$consumer->getRequestToken(
			'http://twitter.com/oauth/request_token',
			CALLBACK_URL);
		$_SESSION['request_token'] =
			$consumer->getToken();
		$_SESSION['request_token_secret'] =
			$consumer->getTokenSecret();
		$this->auth_url =
			$consumer->getAuthorizeUrl(
				'http://twitter.com/oauth/authorize');
	}
	
	/**
	 * 認証完了後にリダイレクトされるコールバックアクション。
	 * verifierでアクセストークンを取得してセッションに保持。
	 * 表示内容はパブリックタイムラインやホームのタイムラインを
	 * 表示するアクション(下にある)へのリンクを表示。 
	 */
	function execute_callback($request) {
		$this->verifier = $_GET['oauth_verifier'];
		$consumer = $this->getConsumer();
		$consumer->setToken(
			$_SESSION['request_token']);
		$consumer->setTokenSecret(
			$_SESSION['request_token_secret']);
		$consumer->getAccessToken(
			'http://twitter.com/oauth/access_token',
			$this->verifier);
		$_SESSION['access_token'] =
			$consumer->getToken();
		$_SESSION['access_token_secret'] =
			$consumer->getTokenSecret();
	}
	
	/**
	 * つぶやく。
	 */
	function execute_tweet($request) {
		$this->status = $request['tweet'];
 		$twitter = $this->getTwitter();
		$this->response =
			$twitter->statuses->update(
				$this->status);
	}
	
	/**
	 * 自分(認証を受けた人)のタイムラインを表示する。
	 */
	function execute_showHomeTimeline($request) {
		$twitter = $this->getTwitter();
		$this->timeline =
			$twitter->statuses->home_timeline();
	}
	
	/**
	 * パブリックタイムラインを表示する。
	 */
	function execute_showPublicTimeline($request) {
		$twitter = $this->getTwitter();
		$this->timeline =
			$twitter->statuses->public_timeline();
	}
	
	/**
	 * Services_Twitterのインスタンスを返す。
	 */
	private function getTwitter() {
		$oauth = $this->getOAuthConsumer();
		$twitter = new Services_Twitter();
		$twitter->setOAuth($oauth);
		return $twitter;
	}
	
	/**
	 * 認証されているかどうかを返す。
	 * セッションでチェックしているに過ぎない。
	 */
	private function isOAuth() {
		return (
			array_key_exists(
				'access_token',
				$_SESSION)
			&& array_key_exists(
				'access_token_secret',
				$_SESSION)
		); 
	}
	
	/**
	 * 認証されたOAuthコンシューマーを返す。
	 */
	private function getOAuthConsumer() {
		$oauth = $this->getConsumer();
		$oauth->setToken(
			$this->access_token);
		$oauth->setTokenSecret(
			$this->access_token_secret);
		return $oauth;
	}
	
	/**
	 * 認証されていないOAuthコンシューマーを返す。
	 * CONSUMER_KEYとCONSUMER_SECRETは、
	 * twitter.confで定義している。
	 */
	private function getConsumer() {
		return
			new HTTP_OAuth_Consumer(
				CONSUMER_KEY,
				CONSUMER_SECRET);
	}
}

いろいろ突っ込みどころが満載のソースだと思いますが、今後徐々に手を入れて行きたいなと。フレームワーク側もイロイロ機能増強が必要だし。

以前の失敗要因は、勘違いとバージョン違いでした。OAuth認証通すためにはServices_Twitter意外にイロイロ必要で、しかもServices_Twitterのバージョンが古かったという不始末。あら恥ずかしいですね(笑)。しかし、今でも「Services_Twitter」でググったら、古い0.4.0の情報が出てくるので無理も無い。最新はPEARから取ってこなアカンのですね。勉強になりました。

それから以前はフレームワーク的なアプローチをしていなかったので、ごちゃごちゃになってしまったというのも大きな要因。

フレームワーク万歳

2012.02.10

PHPで「なんちゃって静的URL」

ジブン用にsymfonyライクで軽量なフレームワーク的なる物をササッと作ろうとしているんだが、契約しているホスティングサーバーではURLの書き換えが出来ず、本質的な問題ではないけど、それでもモジュールやアクションを

http://host/app/index.php?m=module&a=action

などと指定するのは、どう考えてもイケてない。。。と思っていたところ。。。

http://host/app/index.phpに対して、

http://host/app/index.php/module/actionというリクエストをしても、ちゃんとindex.phpが動いて、且つ、要求どおりの(後者の)URLを参照でき、さらに普通のパラメータもちゃんと受け取れる。。。と、昨日はじめて知りました。

「百歩譲ってコレは使える」と書いてみた↓

//URLからモジュールとアクションを抽出
$sma = $_SERVER['PHP_SELF'];
$sma = preg_replace(
  '(^.*/index\.php)', '',
  $sma);
$ma = explode('/', $sma);
while(count($ma) < 3) {
  $ma[] = '';
}
if($ma[1] != '') {
  $module = $ma[1];
}
if($ma[2] != '') {
  $action = $ma[2];
}

//HTMLのbaseディレクトリを決定する
$n = substr_count($sma,'/');
$base_dir='';
for($i = 0; $i < $n; $i++) {
  if($base_dir != '') {
    $base_dir .= '/';
  }
  $base_dir .= '..';
}
$base_dir .= '/';
$base_dir .= $module;
$base_dir .= '/';
$base_dir .= $action;

ベースディレクトリの指定はオプション的なものなんだけど、たとえばモジュールとアクション以降にも静的アドレス的なURLをパラメータ的に続ける仕様にしたとき、強制的にモジュールとアクションの位置にHTMLのベースアドレスを持ってくるために必要。

あんまりやりすぎるとフレームワークが軽量じゃなくなってきそう(笑)

2012.02.07

PHPの文字列連結、ダブルコーテーションとシングルコーテーションの速度比較

perlと同じくPHPでも、文字列をダブルコーテーションで括ると変数の展開が行われる。

処理スピードが遅くなるので「できればシングルコーテーションを使いなさい」とインターネットに書かれていた。

「さもありなんだがホンマかな?」と思ったので、イヤラシイけど確認してみた。

とりあえず変数の展開が行われない場合。。。

ほとんど差が無い。

ありゃ、表とグラフで時間単位が違っているわ(汗; 表のほうの単位がマイクロ秒ですねプログラム見たらグラフの縦軸単位がミリ秒じゃなくて秒ですわ。

回数が多くなると差は1%未満。ダブルコーテーションのほうが速い場合もあるようで少し驚き。回数が少ないほど差が大きいのは、メモリの確保などのオーバーヘッドが影響しているのかもしれない。

実行したスクリプトはこれ。$nに上のグラフの横軸の数値が入る。

<?php
function dqAdd($n) {
	$s = "";
	for($i = 0; $i < $n; $i++) {
		$s .= "0 123456789";
		$s .= "01 23456789";
		$s .= "012 3456789";
		$s .= "0123 456789";
		$s .= "01234 56789";
		$s .= "012345 6789";
		$s .= "0123456 789";
		$s .= "01234567 89";
		$s .= "012345678 9";
		$s .= "0123456789 ";
	}
}
function sqAdd($n) {
	$s = '';
	for($i = 0; $i < $n; $i++) {
		$s .= '0 123456789';
		$s .= '01 23456789';
		$s .= '012 3456789';
		$s .= '0123 456789';
		$s .= '01234 56789';
		$s .= '012345 6789';
		$s .= '0123456 789';
		$s .= '01234567 89';
		$s .= '012345678 9';
		$s .= '0123456789 ';
	}
}
?>

じゃあ変数展開するのと変数を連結するのではどうなるか?とやってみた。

わずかに連結するほうが速い。

わずかといってもだいたい3%くらいの差があるね。回数が少ないほうが差が開くのは上と同じ。

比較したのは以下の処理です。

<?php
function dqAdd($n) {
	$s = "";
	for($i = 0; $i < $n; $i++) {
		$s .= "0$i 123456789";
		$s .= "01$i 23456789";
		$s .= "012$i 3456789";
		$s .= "0123$i 456789";
		$s .= "01234$i 56789";
		$s .= "012345$i 6789";
		$s .= "0123456$i 789";
		$s .= "01234567$i 89";
		$s .= "012345678$i 9";
		$s .= "0123456789$i ";
	}
}
function sqAdd($n) {
	$s = '';
	for($i = 0; $i < $n; $i++) {
		$s .= '0'.$i.' 123456789';
		$s .= '01'.$i.' 23456789';
		$s .= '012'.$i.' 3456789';
		$s .= '0123'.$i.' 456789';
		$s .= '01234'.$i.' 56789';
		$s .= '012345'.$i.' 6789';
		$s .= '0123456'.$i.' 789';
		$s .= '01234567'.$i.' 89';
		$s .= '012345678'.$i.' 9';
		$s .= '0123456789'.$i.' ';
	}
}
?>

これは自宅PCでの結果なんだけど、実は仕事で使っているPCではシングルコーテーションで変数を連結するほうが遅かった。

自宅PCも仕事PCもWindows7。どちらも指数的に処理速度が伸びているように見えたが、ためしにホスティングしているUNIXサーバーでやってみると、自宅PCと同じくシングルコーテーションのほうが速い。でも、どうみてもリニアな処理時間が得られました。メモリの搭載量やプロセッサの数によってこういう差が出るのかも。

通常のプログラムでこれほど一時に大量にループしながら文字を連結することは無いと思うから、もしかしたら回数の少ないほうの速度差が大きいという結果を採用すべきかも。しかし、変数を連結する場合は、マシンによって結果が逆転する場合があるので、一概にどっちが速いといえるものでもないのだろう。

そして、速度差はミリ秒マイクロ秒の世界だけど、検証プログラム全体の処理時間は20秒近くかかっているから、無視できるレベルの差だと思う。総合的に考えて、コーディング時に細かく気にする必要は無いってことだ。気にする分だけ時間の無駄かも。

2012.02.01

[symfony] HTMLタグを含む文字列をエスケープせずに出力する

symfonyでHTMLのタグを記述した文字列($this->str = '<p>文字列</p>'みたいなの)を出力すると、view.ymlでの設定にもよるらしいけど'<''>'が実体参照(それぞれ'&lt;''&gt;')に変換されて結局ブラウザにはHTMLコードがそのまま表示されてしまうんですよね(実は本日知りましたw)

赤い文字を表示したいと思って、以下のようにしてもダメなのね。

//アクション:actions.class.php

public function executeAction(
    sfWebRequest $request)
{
  $this->str =
    '<p style="color:red;">'.
      '文字列</p>';
}
//テンプレート actionSuccess.php
<?= $str ?>
<?php echo $str;?>

これを意図する通り表示させたいなら、テンプレート側で以下のようにすれば良いらしい。

//テンプレート actionSuccess.php
<?= $sf_data->get(
    'str', ESC_RAW) ?>
 

?。いやマジでなんのこっちゃと思いますけど、こうなのだから仕方がない。

通常、アクション側で$this->hogehogeとして使用された変数は、テンプレート側で単に $hogehoge と表記しますけど、果たしてその実体は?というと$sf_data->get('hogehoge')ということなんでしょうな(自信ないけどw)。そして、このgetメソッドは文字列をエスケープして返してくるけど、第二引数にESC_RAWという定数を与えるとエスケープしないってことなのだろうね。と推測した。

が、それだけでは説明が付かない事態。自作のクラスのgetterからHTMLを出力する場合もエスケープされてしまう。困った。

//HogeHogeは自作クラス
$obj = new HogeHoge();
echo $obj->getHtmlString();

これはどう対処するのかというと、、、
↓こうするんだって。

//HogeHogeは自作クラス
$obj = new HogeHoge();
echo $obj->getHtmlString(ESC_RAW);

驚いた。HogeHogeは自作クラスだから、getHtmlStringというメソッドも自作。引数は取らないように宣言しているのに、無理やり身に覚えのないESC_RAWを渡すと、エスケープ無しで返してくれる。つまりsymfonyさんが勝手にいろいろやってくれているんですね。

まさか使い始めて半年経ってこういうことを知る羽目になるとは、symfonyって深いなー。というか変態的だなw
こんなの知らなきゃわからないね。

アンジャッシュのネタが中国にぱくられるとかw。あのダブルミーニング的なネタは中国人でなくてもパクリたくなる気持ちはわかる。

2012.01.27

fetchAllとexecute

DoctrineでSELECT文を実行するのに、無意識にexecuteしてしまっていて、2回目のforeachが回ってくれないという現象にやられました。

$sql="SELECT foo,bar FROM hogeHoge ...";
$con = Doctrine_Manager::connection();
$this->record_list = $con->execute($sql);
                            //↑ここ
foreach($this->record_list as $record) {
    //一回目のループはOK
}
foreach($this->record_list as $record) {
    //二回目はループしない
}

一回のループで済ませるか、fetchAllに変えればOKですね。

実際には一回目のループはオートロードのクラス側で、二回目のループはsymfonyのテンプレート側に書いていました。

それに、「なんで配列がforeachで回らないのか?」という暗澹たる思いにとらわれていましたけど、あとでfetchAllexecuteの戻り値の型を調べてみますと、fetchAllの戻り値は配列ですが、executeの戻り値はPDOStatementというクラスオブジェクトでした。PHPってクラスオブジェクトもforeachにかけられるのですね。

いろんな条件が重なって気づくのが遅れたともいえるなー。

ドクトリンの日本語の本てほとんど無いですねー。
↓これくらいかw

2012.01.20

[symfony] javascriptの読み込み位置(use_javascript と include_javascripts)

Symfonyのテンプレートで外部javascriptを読み込むときは、 use_javascript という組み込みのヘルパーを使えって?それはえらいすんません。でもね、scriptタグで読み込んでる時はちゃんと動いていたんだけれど、use_javascript 使ったら、動かなくなったってーこれはどういうこっちゃろうか?

具体的には、併用しているはずのjQueryがありませんよというエラーが発生。

どうやら取り込み位置がおかしいようだ。HEADを覗くとjQueryより前に依存しているスクリプトが取り込まれている。確かにこれでは動かないが、どうしてこうなるのか?

use_javascriptで検索してみると、Symfonyのチュートリアルの4日目がヒット。読んでみたら、use_javascript とは別に、include_javascripts というヘルパーがあって、なぜかはっきりと書かれていないけど、use_javascript ヘルパーでスクリプトを読み込む位置を指定するみたい。多分これやなと。

ていうか、組み込みのヘルパーのリファレンスって、なんで検索で出てこない?存在しないのかな。チュートリアルを悠々とやっている時間は無いのだと何度言ったら(Ry

ということで、templates/layout.phpを盛大に開いてみると、jQueryはscriptタグでベタに取り込んであって、案の定それよりも前に include_javascripts が置かれていた。

<head>
<?php include_javascripts() ?>
<script
    src="/jquery-ui/js/jquery-1.3.2.min.js"
    type="text/javascript"></script>
</head>

チュートリアルには「パフォーマンスの問題からbodyの閉じタグの直前に include_javascripts を置いておくとよい」と書いてあるけど、関わっているのが途中参加のそれなりに大きい業務システムで、他に影響が出ると責任持てないから、headの閉じタグ直前へ移動。

<head>
<script
    src="/jquery-ui/js/jquery-1.3.2.min.js"
    type="text/javascript"></script>
<?php include_javascripts() ?>
</head>

結果、use_javascript でも正常動作するようになりました。でも本来は以下のようにするべきなんだろうな。

<head>
<?php include_javascripts() ?>
<?php use_javascript('/jquery-ui/js/jquery-1.3.2.min.js')" ?>
</head>

↑こうしておけば問題なかったはずだけど、前任者さんはそんなヘルパーは知らなかったんだろう。他でも use_javascript は一つも使われていなかった。

同じ懸念はCSSでもある(use_stylesheet と include_stylesheets)のだけど、適用されるスタイルの優先順位が逆になるだけですし、妙に見た目がおかしくなっても困るから、とりあえず放置。

2017年3月
      1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31  
フォト

Google AdSense

銀の弾丸

無料ブログはココログ