Hatena::ブログ(Diary)

めざせ言語マスター このページをアンテナに追加 RSSフィード

2011-02-17

php.iniの設定を変えてもファイルをアップロードできないケース

PHPでファイルがアップロードできない場合は、まずphp.iniの下記の設定を疑います。


ディレクティブ名説明
upload_max_filesizeアップロードされるファイルの最大サイズ

アップロードしたいファイルサイズがupload_max_filesizeを超えていたら、それはもうアップロードできません。

そんな時はupload_max_filesizeの設定値を増やしてあげればいいのです。

ただし、この値の変更時は、下記2つの設定値にも注意する必要があります。


ディレクティブ名説明
memory_limitスクリプトが確保できる最大メモリ
post_max_sizePOSTデータに許可される最大サイズ

上記3つの項目が下記のような関係になるように設定しなければいけません。

memory_limit >= post_max_size >= upload_max_filesize


設定値を変える方法はいくつかあります。

例として、ファイルサイズを30MBまで許容する設定にします。

php.iniを直接編集する

/etc/php.ini(保存場所は違う可能性があります)を直接編集します。

実際はこんな風に綺麗に3行並んでません。

memory_limit = 40M
post_max_size = 32M
upload_max_filesize = 32M

.htaccessで設定値をオーバーライドする

対象のディレクトリ.htaccessに下記を記述します。

php_valueであり、php_flagではないので注意!

php_value memory_limit 40M
php_value post_max_size 32M
php_value upload_max_filesize 32M

ini_set関数を使う

ファイルをアップロードするスクリプト内にini_set関数を記述します。

値を○Mと記述する場合は文字列にします。

<?php
ini_set('memory_limit', '40M');
ini_set('post_max_size', '32M');
ini_set('upload_max_filesize', '32M');

これでもダメな場合・・・が、今回ぶち当たった問題でした。

と言っても、原因はあっさりしたもので、サーバ会社側で制限をかけているというだけだったわけですが。

今回のサーバは、WebARENAのSuiteXというプランでした。

よくよく調べたらマニュアルにも書いてありましたね。


というなんともオチが弱く、upload_max_filesizeの設定なんてググればいくらでも同じような内容が出てくるのにまとめた超自己満な内容でした。

まぁまた次同じようなことが起こった時に、可能性の一つとして視野に入れることができれば十分です。


しかし、サーバ会社側ではどうやって制限をかけてるんでしょうか。

解決して満足したので、そこまで調べる気にはなりませんでした(゚∀゚)

2010-09-27

SICP問題1.9

最近FF14にハマってしまい、早くも放置気味のSICPです。

今日はログイン障害で繋がらなかったのでまとめました。

そんなんでいいのか!?

問題

次の二つの手続きはどちらも、引数を1増やす手続きincと、引数を1減らす手続きdecを使って、二つの正の整数を足す方法を定義している。

(define (+ a b)
  (if (= a 0)
    b
    (inc (+ (dec a) b))))

(define (+ a b)
  (if (= a 0)
    b
    (+ (dec a) (inc b))))

置き換えモデルを使い、それぞれの手続が(+ 4 5)を評価する時に生成するプロセスを示せ。

そのプロセスは反復的か再帰的か。

回答

1つ目の手続き

まず1つ目の手続きのプロセスを展開してみます。

(+ 4 5)
(inc (+ 3 5))
(inc (inc (+ 2 5)))
(inc (inc (inc (+ 1 5))))
(inc (inc (inc (inc (+ 0 5)))))
(inc (inc (inc (inc 5))))
(inc (inc (inc 6)))
(inc (inc 7))
(inc 8)
9

こんな感じでいいかな?

ステップごとに遅延演算を作って膨張していき、演算実行時に収縮していきます。

つまり再帰的プロセスと言えますね。

このステップ数はaの値が大きくなるほど増えていくため、aに線形に(比例して)成長すると言えます。

こういうプロセスを線形再帰的プロセスと言います。

再帰何回目で強制的にリターンみたいなものは、線形とは言わないってことかな?

見るからにメモリを食いそうですね〜。

2つ目の手続き

2つ目の手続きは反復的プロセスです。

(+ 4 5)
(+ 3 6)
(+ 2 7)
(+ 1 8)
(+ 0 9)
9

再帰的とは違い、伸び縮みしません。

一定個数の状態変数を更新していき、条件を満たしたら終了するというプロセスです。

再帰的とは違って、見るからにエコっぽいですね。

こちらもステップ数はaに線形なので、線形反復的プロセスといえます。

反復的プロセスは、全ての時点のプロセスの状態を持っているため、途中で止めた場合も、最新の状態変数があればすぐに再開できます。

再帰的プロセスと再帰的手続きの違い

再帰的プロセスと再帰的手続きは名前は似ていますが、意味合いは異なります。

再帰的手続きというのは、構文上で手続きが自身を指していることを言います。

上記2つの手続きは、どちらも+手続きの中で自身である+手続きを指しているので、再帰的手続きと言えます。

しかし、プロセスは上述したとおり、1つ目が再帰的プロセスで、2つ目が反復的プロセスとなっています。

2つ目は再帰的手続きなのに反復的プロセスってややこしいですね。

また、Cなどの通常の言語の実装では、再帰手続きは、プロセスが反復的であっても、手続き呼出の数とともに消費量が増加するようです。

消費量なども含めた完全な反復的プロセスを実装するには下記のループ構造を使用する必要があります。

  • do
  • repeat
  • until
  • for
  • while

Schemeでは、末尾再帰的な実装になっており、上記のような欠点はないそうです。

末尾再帰的についてはまた後ほど出ることを信じて、今は触れないでおきます。

2010-09-20

SICP問題1.8

ここまで来れば今までの応用ですね。

問題

立方根をとるNewton法はyがxの立方根の近似値なら、よりよい近似は

f:id:knowledgetree:20100920094534p:image

の値で与えられるという事実によっている。

この式を使い平方根の手続きと似た立方根の手続きを実装せよ。

解答

平方根の手続きのimprove部分を変えただけです。

(define (improve x y)
  (/ (+ (/ x (* y y))
        (* 2.0 y))
     3.0))

(define (good-enough? improved y)
    (< (abs (- improved y)) 0.001))

(define (crt-iter x y)
  (define improved (improve x y))
  (if (good-enough? improved y)
    improved
    (crt-iter x improved)))

(define (crt x)
  (crt-iter x 1.0))

結果です。

(print (crt 10))

2.154434691772293

(print (crt 100000000))

464.1588833612779

(print (crt 0.001))

0.10000000198565878

google先生との答え合わせも大丈夫そうです。

10^(1 / 3) = 2.15443469

100 000 000^(1 / 3) = 464.158883

0.001^(1 / 3) = 0.1

2010-09-19

SICP問題1.7

説明せよっていう問題が難しいなー。

問題

平方根の計算で使ったgood-enough?テストは、非常に小さい数、非常に大きい数の時に効果的ではない。

それぞれどのようにテストが失敗するか例を使って説明せよ。

good-enough?を実装するもう一つの戦略は、ある繰り返しから次へのguessへの変化に注目し、変化が予測値に比べ非常に小さくなった時に止めるのである。

こういう終了テストを使う平方根手続きを設計せよ。

平方根の求め方については平方根の求め方 - めざせ言語マスターをご覧ください。

解答

非常に小さい数

(sqrt 0.001)を実行すると不十分な状態で終了します。

原因調査のため、以下の部分にprintを仕込みました。

(define (good-enough? guess x)
  (print (format "diff = ~d" (- (square guess) x)))
  (< (abs (- (square guess) x)) 0.001))

下記のような結果になりました。

diff = 0.999

diff = 0.24950024999999992

diff = 0.062126060502996

diff = 0.015285475455254875

diff = 0.0035867199661310497

diff = 7.011851721075595e-4

0.04124542607499115

ちなみに、google先生の出した答えは以下です。

ルート(0.001) = 0.0316227766

元が小さい値なためか、予測値の2乗と被開平数の差がすぐに許容値に達してしまい、十分な近似値を求められていません。

非常に大きい数

(sqrt 10000000000000)を実行すると無限ループになります。

原因調査のため、上記に加え、以下の部分にもprintを仕込みました。

(define (average x y)
  (print (format "average = ~d" (/ (+ x y) 2)))
  (/ (+ x y) 2))

すると、下記結果が出続けます。

average = 3162277.6601683795

diff = 0.001953125

これ以上の近似値は求められないのに、2乗した時の被開平数との差が上記diff分出てしまい、永久に十分と判定されないようです。

解決策

問題にある通り、ある繰り返しから次へのguessへの変化に注目し、変化が予測値に比べ非常に小さくなった時に止めます。

(define (average x y)
  (/ (+ x y) 2))

(define (improve guess x)
  (average guess (/ x guess)))

(define (good-enough? improved guess)
  (< (abs (- improved guess)) 0.001))

(define (sqrt-iter guess x)
  (define improved (improve guess x))
  (if (good-enough? improved guess)
    improved
    (sqrt-iter improved x)))

(define (sqrt x)
  (sqrt-iter 1.0 x))

good-enough?に、改善する前と後の予測値を渡し、その差が許容値内になったら、改善後の予測値を結果としています。

この状態での結果は以下のようになりました。

(print (sqrt 0.001))

0.03162278245070105


(print (sqrt 10000000000000))

3162277.6601683795

許容値を小さくすればもっと精度を高めることができそうです。

2010-09-18

SICP問題1.6

解くのに時間かかったーorz

問題

場合分けの特殊形式としてifとかcondとかあるけど、全部condでいいんじゃね?という輩が、condを使ってifの新盤を定義した。

(define (new-if predicate then-clause else-clause)
  (cond (predicate then-clause)
        (else else-clause)))
(new-if (= 2 3) 0 5)
5
(new-if (= 1 1) 0 5)
0

平方根のプログラムを書き直すのにnew-ifを使った。

(define (sqrt-iter guess x)
  (new-if (good-enough? guess x)
          guess
          (sqrt-iter (improve guess x)
                     x)))

これを実行すると、何が起きるか、説明せよ。

平方根の求め方は平方根の求め方 - めざせ言語マスターをご覧ください。

解答

実行すると無限ループに陥ります。

なぜ無限ループになるのか

まず、new-ifをcondに置き換えて直接使ってみます。

(define (sqrt-iter guess x)
  (cond ((good-enough? guess x) guess)
        (else (sqrt-iter (improve guess x)
                     x))))

問題なく結果が返ってきました。

ifでもcondでも問題がないということは、やっぱりnew-ifに問題があるわけです。

というわけでnew-ifの中でprintしてみました。

(define (new-if predicate then-clause else-clause)
  (print predicate)
  (cond (predicate then-clause)
        (else else-clause)))

・・・何も出ません。

てことはnew-ifにすら来ていない?

new-ifに来る前にこけている!?


そこで思い出しました。

Lispは作用的順序の評価で解釈を行っていることを。


ifやcondのような特殊形式は、まず述語(条件部)を評価し、その条件に合う式を評価して最終的な結果を返します。

しかし、new-ifは特殊形式ではなく、ただの手続きです。

なので、new-ifへの引数は全て渡す前に評価されるのです。

今回の引数の内の(sqrt-iter (improve guess x) x)は再帰手続きなので、new-ifに渡す前に再帰し始めます。

その後も、new-ifを呼び出そうとするたびに、引数の再起手続きが評価されてしまい、永久ループになってしまうのです。


分かってしまえば案外単純な問題ですが・・・分かるまでに時間がかかりました。

Lispは作用的順序の評価で解釈を行っているということは、前の問題にも出てきました。

全ての内容をしっかり理解しておかないと、後々苦労することになりそうです。

平方根の求め方

問題1.6に入る前に平方根の求め方についてまとめておきます。

Newton

平方根を計算するにあたり、通常は次々と近似をとるNewton法を使うらしいです。

数xの平方根の値の予測値yがあれば、yとx/yの平均値をとるという単純な計算で、更に良い予測値が得られます。

最初の予測値を1とし、2の平方根を求めてみます。

予測値平均値
1f:id:knowledgetree:20100918084942p:imagef:id:knowledgetree:20100918084941p:image
1.5f:id:knowledgetree:20100918084940p:imagef:id:knowledgetree:20100918084939p:image
1.4167f:id:knowledgetree:20100918084938p:imagef:id:knowledgetree:20100918084936p:image
1.4142......

この手続を続けると更に良い近似が得られます。

形式化

上記の手続きを形式化してみます。

被開平数(平方根をとろうとする数)の値と予測値の値を決め、予測値が十分になるまで、手順を繰り返します。

(define (sqrt-iter guess x)
  (if (good-enough? guess x)
          guess
          (sqrt-iter (improve guess x)
                     x)))

予測値は、被開平数の前の予測値による商との平均値で改善されます。

(define (improve guess x)
  (average guess (/ x guess)))

平均値は以下で求めます。

(define (average x y)
  (/ (+ x y) 2))

また、予測値が十分になるまでの「十分」も定義しないといけません。

あまり良い方法ではないようですが、結果の二乗と被開平数の差が、前もって決めた許容値(0.001)より小さくなるまで改善し続けます。

(define (good-enough? guess x)
  (< (abs (- (square guess) x)) 0.001))

最後に始め方です。

どんな数の平方根も1であると予測します。

(define (sqrt x)
  (sqrt-iter 1.0 x))

予測値は1ではなく、1.0と表しています。

Schemeでは、整数と小数は区別し、整数の除算は小数ではなく、有理数を作ります。

10/6=5/3

10.0/6.0=1.66666667

もし平方根を1にしてしまうと、xが整数の時に結果が有理数になってしまいます。

有理数と小数の混合演算は小数になるため、1.0にしておきます。


下記のように実行すると、最終的な予測値が帰ってきます。

(sqrt 9)
3.00009155413138

以上が平方根の求め方です。

ここテストに出ます。