我が家の読み聞かせ

はじめに

このエントリーは、お子さん、どんな本読んでる? Advent Calendar 2015 - Adventarの8日目です。

昨日の記事は、id:ohesotori さんの 復刊ドットコムと、赤羽末吉の「おへそがえるごん」 #adventcalender2015 - ここはちょっと見せられない でした。

仕事がひと段落したので、せっかくだから何かAdventCalendarに参加しようと思って探していたところ素敵なテーマを見つけたので参加しました。

珍しく家族ネタです。

2歳の息子が好きな本の中から、悩みに悩んで1冊だけ紹介します。

お気に入りの一冊

あかたろうの1・2・3の3・4・5 (おにのこあかたろうのほん 1)

あかたろうの1・2・3の3・4・5 (おにのこあかたろうのほん 1)

知人からお下がりでいただいた本で、Amazonによると1977年発売なので私よりもちょい年上の本です。

新しい本もたくさんあるのですが、年季の入ったこの本が、なぜかお気に入りです。

出版社の紹介文を引用します。

おにの子のあかたろうが外から帰ってくると、お母さんがいません。そこで、次から次へと電話をかけて、お母さんを追いかけます。 あかたろうの1・2・3の3・4・5 | 偕成社

お母さんを探して家中の部屋をのぞいたり、いろんなところに電話をかけるといった同じことを繰り返すところが楽しいみたいです。

あかたろうが部屋をのぞいてお母さんいないと言っているところでは「いなーい」、電話をすれば「でんわー」「もしもしー」、さかなやさんが出てくれば「さかなー」など、読み聞かせというよりは一緒になって楽しんでます。

よほどフレーズが気に入ってるようで、妻が息子を連れて友人宅にお邪魔した際もトイレのドアを開けて、お母さんいなーいとかやってたそうです。

読み聞かせについて

妻が読んであげることが多いですが、そこそこ早く帰れた平日や週末は私もやります。

ちょっと前までは読み聞かせをしようとしても絵本を自分で持ちたがり、こちらが読んでいてもお構いなしにページをめくりたがりました。
まだ内容が理解できず、目の前にある絵本というモノ自体に興味津々だったのでしょう。

いつの頃からか私や妻が話す間、手を出さずに聞いていられるようになってました。

最近では、お気に入りの本を持って私のところまで来ると、膝の上にちょこんと座って「おんでー(読んでー)」、読み終わると「もっかいおんでー」です。
これが数ターン続きます。
まあ、3回、4回となってくると、別のにしようよと思いますけど。

私が他のことをしていたり、本を手に取らなかったりすると腕をペシペシしながら怒ります。

怒ってるところも含めて、仕草と舌足らずなところががめっちゃかわいいです。

完全に親バカですね。

いつまでこんな風にせがんでくれるかはわからないけど、これからもたくさんの本を一緒に楽しみたいなと思ってます。

どっとはらい

PDOでMySQLに接続するとエラー発生

環境

事象

コード

事象を再現させるための実験コード。
といっても、普通にPDO接続するだけ。

<?php
define('DSN','mysql:host=localhost;dbname=hoge');
define('DB_USER','hoge');
define('DB_PASSWORD','hoge');

try {
  $dbh =  new PDO(DSN, DB_USER, DB_PASSWORD, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
} catch (PDOException $e) {
  echo $e->getMessage();
  exit;
}
結果
SQLSTATE[HY000] [2000] mysqlnd cannot connect to MySQL 4.1+ using the old insecure authentication. Please use an administration tool to reset your password with the command SET PASSWORD = PASSWORD('your_existing_password'). This will store a new, and more secure, hash value in mysql.user. If this user is used in other scripts executed by PHP 5.2 or earlier you might need to remove the old-passwords flag from your my.cnf file

原因

PHP5.3からの下位互換のない変更点に該当しているため。

新しい mysqlnd ライブラリは、MySQL 4.1 用の41バイトの新しいパスワードフォーマットを使用します。 古い16バイトのパスワードを使うと、mysql_connect() 系の関数は次のようなエラーメッセージを生成します。"mysqlnd cannot connect to MySQL 4.1+ using old authentication"

http://php.net/manual/ja/migration53.incompatible.php

要するにMySQLのパスワード設定が古いからのようだ。

対応

管理者ユーザでパスワードを再設定してやればOK。

SET SESSION old_passwords=0;
SELECT * FROM user WHERE user = 'hoge';
UPDATE user SET password = password('XXXXXXXXXXXX') WHERE user = 'hoge';

FuelPHPのUploadクラスを使用するときに注意すること

FuelPHPでファイルアップローダーを作ってた時にちょっとはまったこと。

バージョン

FuelPHP 1.7.2

現象

`upload_max_filesize`、`post_max_size`などを、1GBの設定にしても、400MBのファイルでエラーになる。

原因

FuelPHPのUploadクラスには個別の設定があり、そっちがデフォルトの300MBのままだった。

公式サイトのエラーの説明読んでてたらそれっぽいこと書いてあった。

Upload クラス

UPLOAD_ERR_MAX_SIZE The file uploaded exceeds the maximum file size defined in the configuration.

http://fuelphp.jp/docs/1.7/classes/upload/usage.html#/error_constants

対応

app/config/upload.phpの`max_size`を必要なサイズに変更すればOK。
PHPの設定値より大きくしても意味ないので注意。

	// maximum size of the uploaded file in bytes. 0 = no maximum
	'max_size'			=> 1024 * 1024 * 1024,

2014年振り返り

あっという間に終わった感があるけど、2014年の振り返りを。
今年はほとんどブログ書かなかったなー。

お仕事

1月から新しい職場で働き始めて、Webプログラマ見習いとしてPHPJavaScriptでお仕事してました。

コード書く仕事は半分くらいで、残りはプロジェクトの交通整理的な役割が多かったです。
それほど大きな会社ではないので、割と色々なことをやらせてもらえました。
プロジェクトを進める上では意外と今までの知識や経験が活かせることが多かった気がします。
前職と違った仕事のやり方として、Slackやチャットワークを日常的に使ってますがとてもいい感じです。

ちょうど1年経ちましたが、全体としてはそこそこ楽しく仕事できてます。

プライベート

子どもが1歳5ヶ月になり、どんどん動き回るようになって目がはなせません。
日々子どもが成長するのを見てるのが楽しいです。
子育てのためだけではないですが、勉強会にほとんど参加しませんでした。

自宅ではまとまった時間が取りにくいので、1時間早めに出社して本読んだり写経したりしてます。
おかげで、月1冊ちょっとは読めたみたいです。
慣れてきたのか、子育て手伝いながらの時間の使い方は去年よりは上手くなってるかも。

反省

新しい環境で仕事を始めたこともあって、インプットはそこそこ多くできた気がしますが、アウトプットは少なめでした。
職場と自宅という2つの環境に閉じてしまった感があるので、もう少し別の界隈の人たちとの交流ができたらよかったかな。

特定のファイルがないディレクトリを抽出する

仕事でサーバ設定いじってて、ちょっと悩んだのでメモっておく。
とりあえず目的は達したけど、もっと簡単にできる方法があれば、ぜひ教えてください。

やりたいこと

同じ構成のディレクトリ群の中から、置き忘れる、消されるなどして必要なファイルが存在しないディレクトリを抽出したい。

やったこと

対象ファイルについて存在チェックすれば良いと考えたので、下記のようにディレクトリのリストに対象のファイル名を連結して test コマンドに渡すようにした。
ここでは、hoge/piyo.txt が必要なファイル。
ディレクトリの構成によっては、find に maxdepth オプションも指定した方がいいはず。

[~/tmp/test] $ find .
.
./dir1
./dir1/fuga
./dir1/hoge
./dir1/hoge/piyo.txt
./dir2
./dir2/fuga
./dir2/hoge
./dir3
./dir3/fuga
./dir3/hoge
[~/tmp/test] $ find . -type d -mindepth 2|grep '/hoge$'|awk '{cmd = sprintf("test -e %s/piyo.txt", $0);r = system(cmd);if(r == 1) print $0}'
./dir2/hoge
./dir3/hoge
[~/tmp/test] $

JavaScript と CSS の minify

久々G*関連ネタ。

tree-tips: Gradleでjavascriptをminifyする! | Gradle
tree-tips: Gradleでcssをminifyする! | Gradle

上記サイトのビルドスクリプトを参考に、カレントディレクトリ以下の JavaScriptCSS再帰的に minify するようにした。

ただ、使っているプラグインが新しめの gradle に対応してないっぽくて、ちょっとはまった。
結局 1.7 です。

wrapper 作ったので、ついでにチームの人に紹介しておいた。

defaultTasks 'allMinifyCss', 'allMinifyJs'

apply plugin: 'js'
apply plugin: 'css'

buildscript {
  repositories {
    mavenCentral()
  }
  dependencies {
    classpath 'com.eriwen:gradle-js-plugin:1.5.0'
    classpath 'com.eriwen:gradle-css-plugin:1.2.1'
  }
}

css.source {
  dev {
    css {
      srcDir "./"
        include "**/*.css"
        exclude "**/*.min.*"
    }
  }
}

css.source.dev.css.files.eachWithIndex { cssFile, i ->
  tasks.create(name: "minifyCss${i}", type: com.eriwen.gradle.css.tasks.MinifyCssTask) {
    source = cssFile
    dest = cssFile.getAbsolutePath().replace('.css','.min.css').replace('.js', '.min.js')
    yuicompressor {
      lineBreakPos = -1
    }
  }
}

task allMinifyCss(dependsOn: tasks.matching { Task task ->
    task.name.startsWith("minifyCss")
  }
)

javascript.source {
  dev {
    js {
      srcDir "./"
        include "**/*.js"
        exclude "**/*.min.js"
    }
  }
}

javascript.source.dev.js.files.eachWithIndex { jsFile, i ->
  tasks.create(name: "minifyJs${i}", type: com.eriwen.gradle.js.tasks.MinifyJsTask) {
    source = jsFile
    dest = jsFile.getAbsolutePath().replace('.js', '.min.js')
  }
}
task allMinifyJs(dependsOn: tasks.matching { Task task ->
    task.name.startsWith("minifyJs")
  }
)

task wrapper(type: Wrapper) {
  gradleVersion = 1.7
}

XMLHttpRequest でのリダイレクト処理

XMLHttpRequest でリダイレクトがうまく処理できなくて困ったので調べてみた。

結論

サーバのレスポンスがリダイレクト (30X) の場合、XMLHttpRequest が勝手にリダイレクトしてくれてリダイレクト先のレスポンスが返ってくる。
つまり、転送先が正しければ 200 が返ってくるし、存在しなければ 404 が返ってくるということ。
responseText の中身も転送先の内容になる。

ググってみたけど、探し方が悪いのかちょっと古めの記事しか見つからなかった。
XMLHttpRequestオブジェクトでRedirectをハンドリングするには?(リダイレクトを拾う方法) - on the center line.
ku

結局、上と同じようにレスポンスの内容によって転送と判断して window.location を書き換えて対応した。
XMLHttpRequest では、基本的に同一ドメインアクセスで転送先は分かるはずなのでこれでいいのかなあ。

試したこと

下記のファイルを使って確認してみた。
一応、同期/非同期通信のそれぞれの方式をChromeSafariFirefox 試したけど結果は全て同じ。

使ったファイルと処理の流れ

1. hoge.html から fuga.php へ GET リクエスト。
2. fuga.php が piyo.html へ転送
3. hoge.html のコンソールログに piyo.html のレスポンス表示

hoge.html
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>test</title>
  <script>
    function sync() {
      var xhr = new XMLHttpRequest();
      xhr.open('GET', './fuga.php');
      xhr.send(null);
      console.log(xhr.status);
      console.log(xhr.getAllResponseHeaders());
      console.log(xhr.responseText);
    }
    function async() {
      var xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function () {
        if (xhr.readyState==4){
          console.log(xhr.status);
          console.log(xhr.getAllResponseHeaders());
          console.log(xhr.responseText);
        }
      }
      xhr.open('GET', './fuga.php');
      xhr.send(null);
    }
  </script>
</head>
<body>
  <input type="button" value="sync" onClick="sync()">
  <input type="button" value="async" onClick="async()">
</body>
</html>
fuga.php
<?php
header("Location: ./piyo.html");
piyo.html
piyo.html
レスポンスヘッダ

Accept-Ranges bytes
Connection Keep-Alive
Content-Length 10
Content-Type text/html
Date Sat, 01 Mar 2014 14:03:43 GMT
Etag "5f49f6-a-4f38bc8295bc0"
Keep-Alive timeout=15, max=98
Last-Modified Sat, 01 Mar 2014 13:46:31 GMT
Server Apache/2.2.24 (Unix) DAV/2 PHP/5.5.8

レスポンスボディ

piyo.html