2013年10月15日火曜日

[cakephp] ファイルをダウンロードする

file_get_contentsを使う場合
1
2
3
4
5
6
Configure::write('debug', 0); // デバッグをOFFに
$this->autoRender = false; // オートレンダーをOFFに
$this->header('Content-Type: application/octet-stream');
$this->header('Content-Length: '.filesize($filepath));
$this->header('Content-disposition: attachment; filename="'.$filename.'"');
echo file_get_contents($filepath);
cakephp 1.3 MediaView を使う場合
1
2
3
4
5
6
7
8
9
10
Configure::write('debug', 0); // デバッグをOFFに
$this->view = 'Media';
$params = array(
    'id' => 'example.zip',
    'name' => 'example',
    'extension' => 'zip',
    'download' => true,
    'path' => APP . 'outside_webroot_dir' . DS , // APP/webroot からの相対パスもしくはフルパス
);
$this->set($params);
cakephp 2.X MediaView を使う場合 viewがviewClassとなる しかし2.3で撤廃となっているので2.4以降は次のCakeResponse::downloadを使う
1
2
3
4
5
6
7
8
9
10
Configure::write('debug', 0); // デバッグをOFFに
$this->viewClass = 'Media';
$params = array(
    'id' => 'example.zip',
    'name' => 'example',
    'extension' => 'zip',
    'download' => true,
    'path' => 'files' . DS , // APP/webroot からの相対パスもしくはフルパス
);
$this->set($params);
cakephp 2.4 以降であれば
1
2
3
4
Configure::write('debug', 0); // デバッグをOFFに
$this->autoRender = false; // オートレンダーをOFFに
$this->response->file('files/example.zip'); // APP/webroot からの相対パスもしくはフルパス
$this->response->download('example.zip');

2013年10月1日火曜日

[iOS] iAdのサイズ

iAdのサイズ
iPhoneが縦向きの時は 320×50 points
iPhoneが横向きの時は 480×32 points
iPadが縦向きの時は 768×66 points
iPadが横向きの時は 1024×66 points

[cakephp] PaginatorHelper::conter()の$options['format']の和訳

以下の文をapp/locale/jpn/LC_MESSAGES/default.poに記述する 1.3の場合
1
2
msgid "Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%"
msgstr "全 %pages% 頁中 %page% 頁目 全 %count% 件中 %start% 件~ %end% 件まで %current% 件を表示"
2.xの場合
1
2
msgid "Page {:page} of {:pages}, showing {:current} records out of {:count} total, starting on record {:start}, ending on {:end}"
msgstr "全 {:pages} 頁中 {:page} 頁目 全 {:count} 件中 {:start} 件~ {:end} 件まで {:current} 件を表示"

2013年9月26日木曜日

[cakephp] デバッグレベルが0でもエラーログを取る

以下をbootstrap.phpに書く
1
2
3
4
5
6
if (Configure::read('debug') == 0) {
    error_reporting(E_ALL & ~E_NOTICE & ~E_DEPRECATED);
    ini_set('display_errors', 0);
    ini_set('log_errors', 1);
    ini_set('error_log', LOGS . DS . 'php_error.log');
}

2013年9月25日水曜日

[cakephp] リダイレクトするview

1
2
3
4
5
6
7
<?php $this->Html->scriptStart(array('inline'=>false,'safe'=>false)); ?><!--
setTimeout("link()", 0);
function link()
{
 location.replace('http://www.example.net/thanks.html');
}
//--><?php $this->Html->scriptEnd(); ?>

2013年9月13日金曜日

さくらインターネットで複数のバージョンのPHPを使う。

もしくは、拡張子が.htmlのままPHPのスクリプトを実行させる
最近はphpが5.3以上というフレームワークやwebアプリが増えてきたのでとうとう
さくらインターネットのphpの標準が5.2から5.4になった。
しかし、まだphp5.2でしか動かない古いwebアプリが残っていてphp5.4にすると
そのサイトはワーニングを出すようになってしまった。
せっかくphpが5.4になったのに古いwebアプリの為にダウングレードするのは
大変残念なので、古いwebアプリだけ古いphpを使うようにしてみた。

コマンドラインでの作業になりますので十分注意をすること。
sshで自分のサーバーにログインします。
windowsならputtyとかPoderosaとか、
Macならcodaとかターミナルから
ssh <自分のアカウント>@<自分のアカウント>.sakura.ne.jp
と打ち込めばログインできます。

1
2
3
4
5
6
7
8
%ls -l /usr/local/php
total 16
drwxr-xr-x  7 root  wheel  512 Jul 31 13:11 4.4.9
drwxr-xr-x  7 root  wheel  512 Jul 31 13:11 5.2.17
drwxr-xr-x  7 root  wheel  512 Jul 31 13:11 5.3.27
drwxr-xr-x  7 root  wheel  512 Jul 31 13:12 5.4.17
lrwxr-xr-x  1 root  wheel    6 Jul 23 15:57 cpanel -> 5.2.17
lrwxr-xr-x  1 root  wheel    6 Aug 28 12:02 default -> 5.4.17
5.2.17 5.3.27 5.4.17 が表示された。それぞれphpの5.2 5.3 5.4である。
それぞれのディレクトリ下にbinディレクトリがありその下の目的のものがある。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
%ls -l /usr/local/php/5.2.17/bin 
total 71024
-rwxr-xr-x  1 root  wheel       854 Jul 23 15:58 pear
-rwxr-xr-x  1 root  wheel       875 Jul 23 15:58 peardev
-rwxr-xr-x  1 root  wheel       791 Jul 23 15:58 pecl
lrwxr-xr-x  1 root  wheel        12 Jul 23 15:56 php -> php-mysql5.5
lrwxr-xr-x  1 root  wheel        16 Jul 23 15:56 php-cgi -> php-cgi-mysql5.5
-rwxr-xr-x  1 root  wheel  17975222 Jul 23 15:55 php-cgi-mysql4.0
lrwxr-xr-x  1 root  wheel        16 Jul 23 15:56 php-cgi-mysql5.1 -> php-cgi-mysql5.5
-rwxr-xr-x  1 root  wheel  18324512 Jul 23 15:56 php-cgi-mysql5.5
-rwxr-xr-x  1 root  wheel      2993 Jul 23 15:56 php-config
-rwxr-xr-x  1 root  wheel  17977643 Jul 23 15:55 php-mysql4.0
lrwxr-xr-x  1 root  wheel        12 Jul 23 15:56 php-mysql5.1 -> php-mysql5.5
-rwxr-xr-x  1 root  wheel  18329621 Jul 23 15:56 php-mysql5.5
-rwxr-xr-x  1 root  wheel      4528 Jul 23 15:56 phpize
php何とかがいっぱいある。このなかでファイルサイズの小さい物はリンクなので
大きいものを探す。どうやら本体はphp-cgi-mysql5.5のようだ
これをwww/cgi-binにコピーする。

wwwに移動
ディレクトリcgi-binを作る
cgi-binに移動
先ほどlsで確かめたファイルをコピーする
1
%cp /usr/local/php/5.2.17/bin/php-cgi-mysql5.5 php52.cgi
5.3なら/usr/local/5.3.27/bin/php-cgi-mysql5.5

webサイトのrootの.htaccessに
1
2
Action php52-script /cgi-bin/php52.cgi
AddHandler php52-script .php
の2行を追加する。

.htaccessが無ければ作って保存する。

OSのバージョンが変わったらphp52.cgiを作り直す
そうしないと「Internal Server Error」が出ます。
AddHandler php52-script .php .html
とすると、拡張子が.htmlのままPHPのスクリプトを実行させる時にも使えます。

マルチドメインの場合はフォルダーの下にcgi-binを作り
同じようにコピーして.htaccessを置きます。

2013年6月7日金曜日

[cakphp] 特定のカラムのグループごとの最大値が格納されている行

特定のカラムのグループごとの最大値が格納されている行 「物品ごとに最高値を付けている業者 (複数可) は?」 MySQLのドキュメントによると次のようになる。
1
2
3
4
5
6
7
8
9
10
11
12
13
SELECT article, dealer, price
FROM   shop s1
WHERE  price=(SELECT MAX(s2.price)
              FROM shop s2
              WHERE s1.article = s2.article);
+---------+--------+-------+
| article | dealer | price |
+---------+--------+-------+
|    0001 | B      |  3.99 |
|    0002 | A      | 10.99 |
|    0003 | C      |  1.69 |
|    0004 | D      | 19.95 |
+---------+--------+-------+
これをcakephp風に書き直すと以下のようになる。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
$db = $this->Shop->getDataSource();
$subQuery = $db->buildStatement(
 array(
  'fields' => array('MAX(s2.price)'),
  'table' => $db->fullTableName($this->Shop),
  'alias' => 's2',
  'limit' => null,
  'offset' => null,
  'joins' => array(),
  'conditions' => array('Shop.article' => 's2.article'),
  'order' => null,
  'group' => null,
 ),
 $this->Shop
);
return $this->Shop->find('all',
 array(
  'fields' => array('article', 'dealer', 'price'),
  'conditions' => array(
   "Shop.price = ($subQuery)",
  ),
 )
);

2013年4月4日木曜日

[cakphp 1.3] XMLをを出力する単純な例

  1. 拡張子でリソースの種類を判断できるよう、「{app}/config/routes.php」に Router::parseExtensions()を追加します。
  2. xml用のデフォルトレイアウトビューファイル「{app}/views/layouts/xml/default.ctp」を追加します。
  3. 1
    2
    <?php echo $xml->header(); ?>
    <?php echo $content_for_layout; ?>

    cake bake project すると、{app}/views/layouts に email,js,json,rss,xmlのフォルダーが 自動的に作成されるので必要はないがzipを展開しただけなら無いので作成が必要。

  4. データをXML出力するためのビューファイル「{app}/views/posts/xml/index.ctp」を作成します。
  5. 1
    2
    3
    <?php
    echo $this->Xml->seeialize($posts);
    ?>
  6. コントローラーにコンポーネントRequestHandlerを追加します。
  7. function beforeFilter()を追加します。 rssの時にdebug設定が0でないとContent-Typeがtext/htmlになるようなので、 debug設定を0にしてJSONのときのContent-Typeがapplication/jsonになるようにします。 (4.と5.はapp_controller.phpに設定してしまってもよいかもしれません)
  8. function index()にRSS出力するデータをセットします。
  9. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <?php // {app}/controllers/posts_controller.php
    class PostsController extends AppController {
      var $name = 'Posts';
      var $helpers = array('Html', 'Form');
      var $components = array('RequestHandler');
       
      function beforeFilter() {
        if ($this->RequestHandler->ext == 'xml') {
          Configure::write('debug', 0);
        }
      }
     
      function index() {
        if ($this->RequestHandler->ext == 'xml') {
          $posts = $this->Post->find('all', array('limit' => 20,'order' => 'Post.created'));
          $this->set(compact('posts'));
        }
      }
    }
    ?>
CakePHP(1.3)でJSON出力する単純な例を参考にしました。

2013年3月21日木曜日

[cakephp 1.3] RSSを出力する単純な例

  1. 拡張子でリソースの種類を判断できるよう、「{app}/config/routes.php」に Router::parseExtensions()を追加します。
  2. RSS用のデフォルトレイアウトビューファイル「{app}/views/layouts/rss/default.ctp」を追加します。
  3. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <?php
    echo $this->Rss->header();
     
    if (!isset($channel)) {
     $channel = array();
    }
    if (!isset($channel['title'])) {
     $channel['title'] = $title_for_layout;
    }
     
    echo $this->Rss->document(
     $this->Rss->channel(
      array(), $channel, $content_for_layout
     )
    );
    ?>

    cake bake project すると、{app}/views/layouts に email,js,json,rss,xmlのフォルダーが 自動的に作成されるので必要はないがzipを展開しただけなら無いので作成が必要。

  4. データをRSS出力するためのビューファイル「{app}/views/posts/rss/index.ctp」を作成します。
  5. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <?php
    /* サイト情報の設定 */
     
    $this->set('channel', array(
        'title' =>'サイトタイトル', // サイトのタイトル
        'description' => 'サイトの説明', // サイトの説明
        'link' => array('controller' => 'osusume', 'action' => 'ichiran/tochi'),
      )
    );
     
    echo $rss->items($posts, 'rss_transform');
     
    function rss_transform($item) {
      return array('title' => $item['Post']['title'],
        'link' => array('controller' => 'posts', 'action' => 'view', 'ext' => 'rss', $item['Post']['id']),
        'guid' => array('controller' => 'posts', 'action' => 'view', 'ext' => 'rss', $item['Post']['id']),
        'description' => strip_tags($item['Post']['abstract']),
        'pubDate' => $item['Post']['created'],
      );
    }
     
    ?>
  6. コントローラーにコンポーネントRequestHandlerを追加します。
  7. function beforeFilter()を追加します。 rssの時にdebug設定が0でないとContent-Typeがtext/htmlになるようなので、 debug設定を0にしてJSONのときのContent-Typeがapplication/jsonになるようにします。 (4.と5.はapp_controller.phpに設定してしまってもよいかもしれません)
  8. function index()にRSS出力するデータをセットします。
  9. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <?php // {app}/controllers/posts_controller.php
    class PostsController extends AppController {
      var $name = 'Posts';
      var $helpers = array('Html', 'Form');
      var $components = array('RequestHandler');
       
      function beforeFilter() {
        if ($this->RequestHandler->ext == 'rss') {
          Configure::write('debug', 0);
        }
      }
     
      function index() {
        if ($this->RequestHandler->ext == 'rss') {
          $posts = $this->Post->find('all', array('limit' => 20,'order' => 'Post.created'));
          $this->set(compact('posts'));
        }
      }
    }
    ?>
CakePHP(1.3)でJSON出力する単純な例を参考にしました。

[cakephp 1.3] JSON出力する単純な例

  1. 拡張子でリソースの種類を判断できるよう、「{app}/config/routes.php」に Router::parseExtensions()を追加します。
  2. JSON用のデフォルトレイアウトビューファイル「{app}/views/layouts/json/default.ctp」を追加します。
  3. 1
    <?php echo $content_for_layout; ?>

    cake bake project すると、{app}/views/layouts に email,js,json,rss,xmlのフォルダーが 自動的に作成されるので必要はないがzipを展開しただけなら無いので作成が必要。

  4. データをJSON出力するためのビューファイル「{app}/views/posts/json/index.ctp」を作成します。
  5. 1
    <?php echo json_encode($users) ?>
  6. コントローラーにコンポーネントRequestHandlerを追加します。
  7. debug設定が0でないとContent-Typeがtext/htmlになるようなので、 debug設定を0にしてJSONのときのContent-Typeがapplication/jsonになるようにします。 (4.と5.はapp_controller.phpに設定してしまってもよいかもしれません)
  8. JSON出力するデータをセットします。
  9. 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    <?php // {app}/controllers/posts_controller.php
    class UsersController extends AppController {
      var $name = 'Posts';
      var $helpers = array('Html', 'Form');
      var $components = array('RequestHandler');
       
      function beforeFilter() {
        if ($this->RequestHandler->ext == 'json') {
          Configure::write('debug', 0);
        }
      }
     
      function index() {
        if ($this->RequestHandler->ext == 'json') {
          $posts = $this->Post->find('all', array('limit' => 20,'order' => 'Post.created'));
          $this->set(compact('posts'));
        }
      }
    }
    ?>
CakePHP(1.3)でJSON出力する単純な例を参考にしました。

2013年3月18日月曜日

[cakephp 1.3] index.htmlで表示できるようにする。もしくは routes.phpにRouter::parseExtensions()を追加すると。

まず、config/routes.phpにRouter::parseExtensions();を追加します。
こうすると普通のページを表示したとき、$this->params['url']['ext']に'html'が必ず付加されるようになります。
どういうことになっているかというと、
http://example.com/top/view が http://example.com/top/view.html と同じ扱いになる。
普通 http://example.com/top/view.html とすると、function view.html(){}が無いのでエラーになるが、
Router::parseExtensions();を追加するとエラーにはならず、
http://example.com/top/view.html とすると function view(){} を実行する。

2013年2月21日木曜日

[mpdf56] PDF出力をゴシックで

1146行からはマルチバイトの修正、10466行からは小塚明朝から小塚ゴシックへの変更


mpdf.php
1146    if (preg_match('/([\-+])aCJK/i',$mode, $m)) {
1147        preg_replace('/([\-+])aCJK/i','',$mode);
1148        if ($m[1]=='+') { $this->useAdobeCJK = true; }
10465    $family='sjis';
10466    $name='KozMinPro-Regular-Acro'; 
10467    $cw=$this->SJIS_widths;


mpdf.php
1146    if (preg_match('/([\-+])aCJK/i',$mode, $m)) {
1147        // bug? preg_replace returns replaced value!
1148        //preg_replace('/([\-+])aCJK/i','',$mode);
1149        $mode = preg_replace('/([\-+])aCJK/i','',$mode);
1150        if ($m[1]=='+') { $this->useAdobeCJK = true; }
10467    $family='sjis';
10468    //$name='KozMinPro-Regular-Acro'; 
10469    $name='KozGoPro-Medium';
10470    $cw=$this->SJIS_widths;

42行からはCJKをtrueにします。270行からは標準フォントをserifからsans-serifに変更。

config.php
42
43$this->useAdobeCJK = false;        // Uses Adobe CJK fonts for CJK languages
44            // default TRUE; only set false if you have defined some available fonts that support CJK
270    'BODY' => array(
271        'FONT-FAMILY' => 'serif', 
272        'FONT-SIZE' => '11pt',


config.php
42
43$this->useAdobeCJK = true;        // Uses Adobe CJK fonts for CJK languages
44            // default TRUE; only set false if you have defined some available fonts that support CJK
270    'BODY' => array(
271        'FONT-FAMILY' => 'sans-serif', 
272        'FONT-SIZE' => '11pt',

[mac osx] ゴミ箱が機能しなくなった。

ゴミ箱にいれると即削除されるようになってしまった。
どうやら ~/.Trash のパーミッションが変わってしまったらしい。
なぜかオーナーが root になっていた。
原因がわかってしまえば対処方は簡単
sudo chown -R 自分 ~/.Trash

2013年2月18日月曜日

[cakephp 1.3] Button or Submit

<input type="button">を作りたかったんだけど $this->Form->input('button',array('type'=>'button');としても <button></button>しかできないし、困っていたんだけど、色々やってみたら 解決したので書いておく。

このように書くと
1
2
3
4
echo $this->Form->submit('送信',array('type'=>'button','div'=>false,'label'=>false));
echo $this->Form->submit('送信',array('type'=>'submit','div'=>false,'label'=>false));
echo $this->Form->button('送信',array('type'=>'button','div'=>false,'label'=>false));
echo $this->Form->button('送信',array('type'=>'submit','div'=>false,'label'=>false));
このように出力されます。
1
2
3
4
<input type="button" value="送信" />
<input type="submit" value="送信" />
<button type="button">送信</button>
<button type="submit">送信</button>

[cakephp 1.3] 本当に削除してもいいですか?

1
2
3
4
echo $this->Form->button('削除', array(
'type' => 'button',
'onClick' => "if(confirm('削除しますか?')){location.href='". $this->Html->url(array('controller' => 'estates','action'=>'delete',$result['Estate']['id'],))."';}"
));

2013年2月8日金曜日

[mysql] update 結合したテーブルの値のコピー

1
2
3
UPDATE  `bukken_commons` ,`bukken_sells`
SET  `bukken_commons`.`commercial_medium` =  `bukken_sells`.`baitai`
WHERE  `bukken_commons`.`bukken_id` =  `bukken_sells`.`bukken_id`