utf8で3キャリア対応サイトを作成する際に、auの絵文字が小さくならない件の対応 (php emoji utf8
cakePHP + smarty + 絵文字表示 - 雑想空間 これの続き、っちゃー続き。
auの絵文字を表示させる方法は何種類かあるんですが、imgタグで表示させると、fontタグやspanタグのstyleでサイズ指定しても、連動して小さくなってくれません。
au絵文字を大きくする、小さくする - [au [KDDI EZweb]/携帯] ぺんたん info
こちらにも書いてあるように、
 
このように書けばokですが、
<img localsrc="51" />
imgタグで指定すると、サイズが固定されて、変動しません。
cake php + smarty
cake php と smarty を利用してサイトを作成した時に、
Smarty で携帯絵文字 - ZeBeVogue別館
こちらの関数にお世話になったのですが、
case "e"; if (preg_match("/[^0-9]/", $emoji_array[$data][2])) { $put = $emoji_array[$data][2]; } else { $put = "<img localsrc=\"".$emoji_array[$data][2]."\" />"; } break;
基本的には、imgタグで表示するので、文字サイズとともにサイズ変更してくれません。
webコード(SJIS)で書き直そうと思い、規則性やマッピングについて久々に探したら、2007年にすでに解決してました。
KDDI/AUでutf-8のHTMLフォームから送られてくる絵文字コード - Bulknews::Subtech - subtech
EZweb (au) 絵文字の規則性 - 覇王色を求めて
utf-8のサイトでformから送信された場合の対処法をまとめてありますが、普通にwebコード(SJIS)からエンコードしなおす場合にも利用できそうです。
<?php // eebd89 echo bin2hex(mb_convert_encoding(pack('H*', dechex(hexdec("F649") - 1792)), 'UTF-8', 'unicode')); ?>
ちょっと書き換え
まず絵文字のマッピング表に、新たに、auのwebコード(SJIS)を追加します
表は
絵文字を使いこなして見るためのページ【Docomo】全ページ
こちらから拝借
1,,44,Gj,F660 2,,107,Gi,F665 3,,95,Gk,F664 4,,191,Gh,F65D
末尾に追加してみました。
コードもちょっと変えます
23 // au の絵文字表示形式 24 $au_conv = 1; // 0 default 1 size依存 25 26 //携帯UA取得 27 $agent = $_SERVER["HTTP_USER_AGENT"]; 28 if(preg_match("/[0-9]{1,3}/", $data) && is_numeric($data) && 0 < $data && $data < 253) { 29 switch (mobile($agent)) { 30 case "i"; 31 $put = $emoji_array[$data][1]; 32 break; 33 case "e"; 34 if ($au_conv == 1) { 35 if (preg_match("/^[A-F0-9]+$/", $emoji_array[$data][4])) { 36 $put = mb_convert_encoding(pack('H*', dechex(hexdec($emoji_array[$data][4]) - 1792)), 'UTF-8', 'unicode'); 37 } 38 else { 39 $put = $emoji_array[$data][4]; 40 } 41 } 42 elseif (preg_match("/[^0-9]/", $emoji_array[$data][2])) { 43 $put = $emoji_array[$data][2]; 44 } else { 45 $put = "<img localsrc=\"".$emoji_array[$data][2]."\" />"; 46 } 47 break; 48 case "s"; 49 if (preg_match("/^[A-Z]{1}?/", $emoji_array[$data][3])) { 50 $put = "\x1B\$".encode($emoji_array[$data][3])."\x0F"; 51 } else { 52 $put = encode($emoji_array[$data][3]); 53 } 54 break; 55 case "p"; 56 $put = "<img src=\""."/img/mobile/".$emoji_array[$data][0].".gif\" width=\"12\" height=\"12\" border=\"0\" alt=\"\" />"; 57 break; 58 }
これで
{emoji num=1}
で、絵文字表示できて、文字サイズに依存する絵文字が出ました
MacPorts メモ
MacPorts
Snow Leopard に MacPorts いれる
メモ
Xcode
まずはXcodeがいるので、入れる
Mac本体に付属のOSインストールディスクか
Sign in with your Apple ID - Apple Developer
からinstallする。
Developer Toolsの中になるかな。
AppleIDなければ、作成から。
結構重いので、気長にモンハンでも狩りながら待つ事。
MacPorts
403 Forbidden
ここからも落とせるが、Snow Leopard対応のVersionは、本家から落とした方が良い。
The MacPorts Project -- Home
こっち。
sudo port selfupdate sudo port sync
PATH
.bash_profile に、
# MacPorts Installer addition on yyyy-mm-dd_at_hh:mm:ss: adding an appropriate PATH variable for use with MacPorts. export PATH=/opt/local/bin:/opt/local/sbin:$PATH # Finished adapting your PATH environment variable for use with MacPorts.
って適当に追加されているので、
source ~/.bash_profile
なんか入れてみる
sudo port install git-core
Error: db46 requires the Java for Mac OS X development headers.
db46のinstallに失敗した
Error: db46 requires the Java for Mac OS X development headers. Error: Download the Java Developer Package from: <https://connect.apple.com/cgi-bin/WebObjects/MemberSite.woa/wa/getSoftware?bundleID=20719> Error: Target org.macports.configure returned: missing Java headers Error: Failed to install db46
言われた通り、別途入れる
Sign in with your Apple ID - Apple Developer
AppleIDいるよ。
入れたら、やり直せば、成功した。
狩りを止めて、コーディングに戻れば完成。
レンサバの環境構築メモ[sakuraインターネット]
さくらのレンサバを借りたので、環境を作るメモ
bash
さくらはデフォルトシェルがcshらしい。
使い慣れてるbashに変えてみる。
まずは利用可能なシェルを見る
% cat /etc/shells /bin/sh /bin/csh /bin/tcsh /usr/local/bin/bash /usr/local/bin/rbash /usr/local/bin/zsh /usr/local/bin/rzsh /usr/bin/passwd
% chsh -s /usr/local/bin/bash Password: # パスワードを入力
.bash_profile
.bashrc
を適当に作成。
vim
wget ftp://ftp.vim.org/pub/vim/unix/vim-7.0.tar.bz2
wget ftp://ftp.vim.org/pub/vim/extra/vim-7.0-extra.tar.gz
wget ftp://ftp.vim.org/pub/vim/extra/vim-7.0-lang.tar.gz
tar jxvf vim-7.0.tar.bz2
tar zxvf vim-7.0-extra.tar.gz
tar zxvf vim-7.0-lang.tar.gz
cd vim70
mkdir patches
cd patches
curl -O 'ftp://ftp.vim.org/pub/vim/patches/7.0/7.0.[001-243]'
cd ..
cat patches/7.0.* | patch -p0
./configure --enable-multibyte --enable-xim --enable-fontset --with-features=big --prefix=/home/ryoff
make && make install
vi .bashrc
alias vi='~/bin/vim'
source ~/.bashrc
screen
wget ftp://ftp.uni-erlangen.de/pub/utilities/screen/screen-4.0.3.tar.gz
tar xzf screen-4.0.3.tar.gz
cd screen-4.0.3
./configure --prefix=/home/user_name
make && make install
yyyymmddhhiiss形式を日付け変換する時の php4 php5 の方法
日付け変換
yyyymmddhhiiss形式の文字列を日付けに変換したかったです。
つまり
echo date("YmdHis", time())."\n";
これ実行して出てくる文字列をふたたびdate関数に渡せるようにしたかった感じ。
strtotime
最も単純に使ってみました。
1 <?php 2 3 $time = date("YmdHis", time()); 4 echo strtotime($time)."\n"; 5 echo date("Y/m/d H:i:s", strtotime($time))."\n"; 6 7 ?>
結果は php5 と php4 で違いました。
php5.2
[ryoff@php5-ryoff ~/mycode/php5]$ php strtotime.php 1287109712 2010/10/15 11:28:32
php4.3
[ryoff@php4-ryoff ~/mycode/php4]$ php strtotime.php -1 1970/01/01 08:59:59
strtotimeの時点で、-1帰ってくるなぁ。
php4ではうまく動いてくれなかったので、力技....
1 <?php 2 3 $time = date("YmdHis", time()); 4 echo strtotime($time)."\n"; 5 echo sprintf("%04d/%02d/%02d %02d:%02d:%02d", 6 substr($time, 0, 4), substr($time, 4, 2), 7 substr($time, 6, 2), 8 substr($time, 8, 2), substr($time, 10, 2), 9 substr($time, 12, 2) 10 )."\n"; 11 12 ?>
雑感
どうでもいいけど、
"Y/m/d H:i:s"
って、
ヤマダ電機! HIS!
って読めるよね。
覚えやすいですね。
local::libのinstallメモ
local::lib を今更ながらinstallしたので、その作業メモ
参考サイト
local::libを使った非rootでのCPAN環境構築 - hide-k.net#blog
第18回 local::lib:ふだんと違う環境でPerlを使う|gihyo.jp … 技術評論社
基本はhide-kさんのサイトの手順どおりに行った。
落としてきて、解凍。
wget http://search.cpan.org/CPAN/authors/id/A/AP/APEIRON/local-lib-1.003001.tar.gz tar xzvf local-lib-1.003001.tar.gz cd local-lib-1.003001
BSDPANのエラーを回避する設定
export PKG_DBDIR=$HOME/local/var/db/pkg export PORT_DBDIR=$HOME/local/var/db/pkg export INSTALL_AS_USER export LD_LIBRARY_PATH=$HOME/local/lib mkdir -p ~/local/var/db/pkg
cpanの初期設定
sudo cpan .... exit;
perl MakeFile.PL --bootstrap=$HOME/local
なんかエラー出た
--2010-10-02 20:02:42-- ftp://ftp.dti.ad.jp/pub/lang/CPAN/authors/id/A/AN/ANDK/CHECKSUMS.gz (try:20) => `-' Connecting to ftp.dti.ad.jp|202.216.228.228|:21... connected. Logging in as anonymous ... Error in server response, closing control connection. Giving up. Issuing "/usr/bin/ftp -n" Trying 202.216.228.228... Not connected. Not connected.
ミラーサイトにつなげない。
CPANに失敗する時のよくある解決策として
export FTP_PASSIVE=1
とあったが、ダメ。
しょうがないので、ミラーサイトを変える。
cpan初期化&再設定
cpan o conf init .... .... o conf commit
基本的に全部OK。
地域を日本に設定して、ミラーサイト変える。
再実行
perl MakeFile.PL --bootstrap=$HOME/local
成功
make && make test
All tests successful. Files=2, Tests=6, 0 wallclock secs ( 0.05 usr 0.01 sys + 0.04 cusr 0.01 csys = 0.11 CPU) Result: PASS
問題なさそうなので、install
make install
Ethna v2.5.0のソースコードを読み解く Part1 【Ethna_ActionForm.php】
ethnaで書いてて、ふと思った
$hoge = $this->af->get('hoge');
で、hogeが渡されてこなかった場合、$hogeにはnullが入るのか?空が入るのか?
書けばすぐに分かるけど、せっかくなのでEthnaの元コード読んで見る事に
download
404 Not Found - Ethna
download && install 情報は公式に詳しくて書いてあります。
とりあえず、wgetして落として解凍
[ryoff@ryoff ~/ethna]$ tree -L 2 . |-- Ethna-2.5.0 | |-- CHANGES | |-- Ethna.php | |-- LICENSE | |-- README | |-- bin | |-- class | |-- misc | |-- skel | |-- test | `-- tpl `-- package.xml
ControllerやActionClass、ActionFormなどは、class以下にあります。
Ethna_ActionForm.php
$this->af
とあるように、afはActionFormの略です。
なので、
を読みます。
get
132 /** 133 * フォーム値のアクセサ(R) 134 * 135 * @access public 136 * @param string $name フォーム値の名称 137 * @return mixed フォーム値 138 */ 139 function get($name) 140 { 141 return $this->_getVarsByFormName($this->form_vars, $name); 142 }
$nameを受け取って、 $this->form_vars と $name を _getVarsByFormName関数に渡していますね。
その引数を返す、と。
form_vars
_getVarsByFormName関数を見るまえに、form_varsという変数を覗きましょう。
form_varsは40行目に初期値が定義されてます。
39 /** @var array フォーム値 */ 40 var $form_vars = array();
この変数に値をsetしているのは、setFormVars関数です。
299 /** 300 * ユーザから送信されたフォーム値をフォーム値定義に従ってインポートする 301 * 302 * @access public 303 */ 304 function setFormVars() 305 { 306 if (isset($_SERVER['REQUEST_METHOD']) == false) { 307 return; 308 } else if (strcasecmp($_SERVER['REQUEST_METHOD'], 'post') == 0) { 309 $http_vars =& $_POST; 310 } else { 311 $http_vars =& $_GET; 312 } 313 314 // 315 // ethna_fid というフォーム値は、フォーム定義に関わらず受け入れる 316 // これは、submitされたフォームを識別するために使われる 317 // null の場合は、以下の場合である 318 // 319 // 1. フォームヘルパが使われていない 320 // 2. 画面の初期表示などで、submitされなかった 321 // 3. {form name=...} が未設定である 322 // 323 $this->form_vars['ethna_fid'] = (isset($http_vars['ethna_fid']) == false 324 || is_null($http_vars['ethna_fid'])) 325 ? null 326 : $http_vars['ethna_fid']; ...... ......
なのですが、この関数はEthna_ActionForm内からは呼ばれていません。
呼び出し元は、同ディレクトリ内になるEthna_Controllerからです。
./class/Ethna_Controller.php
_trigger_WWW関数内でsetFormVars関数が呼び出されています。
897 /** 898 * フレームワークの処理を実行する(WWW) 899 * 900 * 引数$default_action_nameに配列が指定された場合、その配列で指定された 901 * アクション以外は受け付けない(指定されていないアクションが指定された 902 * 場合、配列の先頭で指定されたアクションが実行される) 903 * 904 * @access private 905 * @param mixed $default_action_name 指定のアクション名 906 * @param mixed $fallback_action_name アクション名が決定できなかった場合に実行されるアクション名 907 * @return mixed 0:正常終了 Ethna_Error:エラー 908 */ 909 function _trigger_WWW($default_action_name = "", $fallback_action_name = "") 910 { ..... ..... 949 // アクションフォーム初期化 950 // フォーム定義、フォーム値設定 951 $form_name = $this->getActionFormName($action_name); 952 $this->action_form =& new $form_name($this); 953 $this->action_form->setFormDef_PreHelper(); 954 $this->action_form->setFormVars(); 955 $backend->setActionForm($this->action_form);
_trigger_WWW関数はethnaのメインの処理を行います。
こちらはまた別途読み解いてみます。
今回は、
Controller 内で関数が呼び出されて、htmlのformに入力された値がform_varsにセットされるんだな
ぐらいに思っておきます。
前置きが長くなりましたが、これで、_getVarsByFormName関数に渡す、$this->form_varsという値には、htmlのFormに入力された値がセットされていることが分かりました。
_getVarsByFormName
206 /** 207 * 配列の中からキーで指定された要素を取り出す 208 * 209 * @access private 210 * @param array &$target 対象とする配列 211 * @param string $nane キー 212 * @return string 指定された要素 213 */ 214 function _getVarsByFormName(&$target, $name) 215 { 216 $keys = $this->_getFormNameArray($name); 217 return $this->_getVarsByKeys($target, $keys); 218 }
_getFormNameArray関数に$nameを渡して$keysを受け取り、
_getVarsByKeys関数に$targetと$keysを渡して、戻り値を返しています。
_getVarsByKeys関数で返される値がそのまま
$this->af->get('hoge');
で返される値なので、この二つの関数を読み解けば、戻り値のパターンが分かりそうです。
_getFormNameArray
185 /** 186 * フォーム名に対応するキーの配列を返す 187 * 188 * @access private 189 * @param string $name フォーム名 190 * @return array キーの配列 191 */ 192 function _getFormNameArray($name) 193 { 194 // 多次元配列を指定した場合 195 if (preg_match('/^.*\[[^\]]+\]$/', $name)) { 196 $buff = preg_replace('/\]\[/', '[', $name); // hoge[foo][bar] => hoge[foo[bar] 197 $buff = preg_replace('/\]/', "", $buff); // hoge][foo[bar] => hoge[foo[bar 198 $ret = explode('[', $buff); // hoge[foo[bar => array('hoge', 'foo', 'var') 199 } else { 200 // 多次元配列を指定していない場合 201 $ret = array($name); 202 } 203 return $ret; 204 }
多次元配列を指定した場合と指定していない場合で、処理が分かれています。
多次元配列を渡すとは、具体的にどんな事をしてくれるのか。
公式サイトに答えが書いてあります。
フォーム定義を以下のように [] 付きのキーで分類して定義するだけです。例を以下に示します。 [phone][home]や、[phone][mobile] のように、複数の階層を使って定義することも可能です。 ※テンプレートの例 <form method="post"> <input type="text" name="User[name]" value="宮崎あおい" /> <input type="text" name="User[phone][home]" value="01-2345-6789" /> <input type="text" name="User[phone][mobile]" value="090-1234-5678" /> <input type="submit"> </form>
サンプルに宮崎あおい、と使用するあたり、非常に好感が持てます。
そして、この方法で、User[name] User[phone]などと階層の途中からでも値を取得できます。
$this->af->get('User[name]') $this->af->get('User[phone]')
こんな感じ。
196〜198行目で多次元配列をexplodeして、配列にしてますね。
_getVarsByKeys
引き続き、_getVarsByKeys関数です。
_getFormNameArray関数で配列になって戻った$keysを順次処理していきます。
235 /** 236 * 配列の中からキーで指定された要素を取り出す 237 * 238 * @access private 239 * @param array &$target 対象とする配列 240 * @param array $keys キーの配列 241 * @return string 指定された要素 242 */ 243 function _getVarsByKeys(&$target, $keys) 244 { 245 $count = count($keys); 246 if ($count == 0) { // 探索完了 247 return $target; 248 } elseif ($this->max_form_deps + 1 <= $count) { // 深すぎる配列を制限する 249 return null; 250 } 251 252 // まだ探索するキーが残っている 253 $curval = array_shift($keys); 254 if (is_array($target) && array_key_exists($curval, $target)) { 255 return $this->_getVarsByKeys($target[$curval], $keys); 256 } 257 return null; 258 }
max_form_deps はデフォルトでは10階層となっているようです。
$target(=form_vars) 内から、$keysに相当するデータを取得しています。
$keysがなくなるまで、再帰処理してますね。
つまり結果は、
それぞれ帰ります。
関数まねして動かしてみると、
1 <?php 2 3 $param = array( 4 'a' => 1, 5 'b' => array( 6 'c' => 2, 7 'd' => array( 8 'e' => 3, 9 ), 10 ), 11 ); 12 function getVarsByKeys(&$param, $keys) { 13 $count = count($keys); 14 if ($count == 0) { 15 return $param; 16 } 17 18 $curval = array_shift($keys); 19 if (is_array($param) && array_key_exists($curval, $param)) { 20 return getVarsByKeys($param[$curval], $keys); 21 } 22 return null; 23 } 24 25 var_dump(getVarsByKeys($param, array('a'))); 26 // int(1) 27 var_dump(getVarsByKeys($param, array('b'))); 28 // array(2) { 29 // ["c"]=> 30 // int(2) 31 // ["d"]=> 32 // array(1) { 33 // ["e"]=> 34 // int(3) 35 // } 36 // } 37 var_dump(getVarsByKeys($param, array('b','d','e'))); 38 // int(3) 39 var_dump(getVarsByKeys($param, array('b','d','f'))); 40 // NULL 41 42 ?>
な感じ。
cakePHP とsmartyを使い、html helperで日本語を使うためのメモ
苦労したので、次のためにメモ
初期
cakePHPとsmarty使う方法は
第11回 Smartyとフレームワーク(その1:CakePHP編) - Smarty講座
これ見ればいけるので、省略。
んで、このなかで巧く動かない部分があった。
以下のコードを先ほどのindex.tplに書いてみてください。 {$html->link('yossy先生のSmarty講座', 'http://www.phppro.jp/school/smarty/')} http://(ドメイン名)/test/index にアクセスしてみて、リンクは表示されたでしょうか?
「いいえ」
<a href="http://www.phppro.jp/school/smarty/"></a>
こんな感じで、リンク名が入らない
ちなみに、リンク名を英数字だけにすると
<a href="http://www.phppro.jp/school/smarty/">test</a>
入る。
原因は..
正直よくわからん。
cakeのversionかもしれないし、smartyのversionかもしれないし、レンサバのPHPのversionかもしれん。。
とりあえず日本語使えるようにしようと思って、試行錯誤。
日本語だけ動かないので、きっと日本語入れた場合に、へんなencoding処理とかしてるんだろうなと思い、cakeのhtml helperのソースを読みに行く
html_helper
ファイルは
- cake/libs/view/helpers/html.php
260行目
/** * Creates an HTML link. * ....... function link($title, $url = null, $options = array(), $confirmMessage = false) { $escapeTitle = true; if ($url !== null) { $url = $this->url($url); } else { $url = $this->url($title); $title = $url; $escapeTitle = false; } if (isset($options['escape'])) { $escapeTitle = $options['escape']; } if ($escapeTitle === true) { $title = h($title); } elseif (is_string($escapeTitle)) { $title = htmlentities($title, ENT_QUOTES, $escapeTitle); }
$escapeTitleっての怪しいな。
三つ目の引数の$options内に、"escape"を定義して渡してあげればいいのか。
渡した"escape"は$escapeTitleに入って、htmlentities関数の第三引数に読まれて、$titleに入る。
なんかあやしそうだから、$optionsに"escape"を定義してみる
htmlentitiesの第三引数はcharsetらしいので、"EUC-JP"を定義する
{$html->link('入口', 'http://hoge.com/pages/home', array('escape' => 'EUC-JP'))}
Fatal Error (256): Smarty error: [in /home/hogehogehoge/app/views/tops/index.tpl line 11]: syntax error: unrecognized tag: $html->link('yossy先生のSmarty講座', 'http://www.phppro.jp/school/smarty/', array('escape' => 'EUC-JP',)) (Smarty_Compiler.class.php, line 446) [APP/vendors/smarty/Smarty.class.php, line 1093]
なんかエラーでる。
今度はこのエラー調べる
CakePHP で Smarty を使用するメモ | Sun Limited Mt.
こちらのサイト様で
ただ、.thtml で HTMLヘルパーを使用している場合 {$html->input('Post/name', array('size'=>'30'))} のままでは、array(…) でエラーになる。
「はい。同じくarray(...)でエラーになります。。」
というわけで、解決方法として紹介されているpluginを導入してみる。
プラグインは↓
function.assign_assoc.php という名前で保存して、
/vendors/samrty/libs/plugins/
以下に保存。
今度はtpl内で
{assign_assoc var='ArrayName' value='escape=>EUC-JP'} {$html->link('yossy先生のSmarty講座', 'http://www.phppro.jp/school/smarty', $ArrayName)}
と記述すれば完成。
日本語のリンク名が出ましたよ。