タグ別アーカイブ: PHP

PHPのforeachループで配列の要素を評価、除去する

今回はPHPの小ネタです。

PHPのforeachは、配列内の要素一つ一つに対して同じ処理を適用する際に便利です。構文は、以下の二種類です。

//構文1
foreach(配列 as 値を入れる変数){
処理
}
 
//構文2
foreach(配列 as キー値 => 値を入れる変数){
処理
}

構文1では配列内要素の値をそのまま順番に取得して変数に入れます。たとえば、”りんご”,”ごいさぎ”,”ぎんやんま”という3要素をもつ配列$Septemberがあったとき、

foreach($September as $value){
$value .= "?";
echo $value;
}

結果、りんご?ごいさぎ?ぎんやんま?が出力されます。これはあくまで値を変数に格納しているだけですので、元の配列$Septemberを処理終了後ダンプしてみても、内部の要素は”りんご”,”ごいさぎ”,”ぎんやんま”のままです。
元の配列の要素を変更する場合は、構文2を使います。

foreach($September as $key => $value){
$September[$key] .= "?";
}

これで$Septemberをダンプすると”りんご?”,”ごいさぎ?”,”ぎんやんま?”となっています。
この挙動は、元からキー値つきで宣言された配列に関しても同じです。

$September = array("果物" => "りんご","鳥" => "ごいさぎ","虫" => "ぎんやんま");
foreach($September as $key => $value){
$September[$key] .= "?";
}
 
//$Septemberは("果物" => "りんご?","鳥" => "ごいさぎ?","虫" => "ぎんやんま?")

配列の要素の改変についてはこれでOKですが、配列の要素を評価して削除する場合にはどのようにすればいいのか。要素を削除することでループのインデックスが変わってしまって不都合になるのではないかと心配しましたが、思いつくままunsetを使って、特に問題ない結果を得られました。

foreach($September as $key => $value){
if($September[$key] == "ごいさぎ"){
unset($September[$key]);
}
}
 
//$Septemberは、("りんご","ぎんやんま")

ただし、この場合配列のインデックスが歯抜けになってしまいますので、連番のインデックスに戻したい場合には、array_values関数を使わないといけません。
カンマ区切りで保存してあるデータを取り出し、explodeしたあとforeach内で評価、特定の値のものを削除してimplodeで元に戻す。といった処理の流れで使えそうです。


Conceptual:Ajax対応CSV表示プログラムOnlyCSViewを計画する

以前、PHPの便利なfgetcsv関数を使ったCSV表示プログラムを書きました。このプログラムはソースコードを読んで判るように、フォームで受け取ったパスのファイルを一時ファイルとしてコピーし、関数に与え処理した結果をページの再読み込み時に表示という手順を踏んでいます。もちろんPHPはサーバサイドで呼ばれるので、結果の表示に最低一回の画面遷移を必要とするnon-Ajaxなプログラムです。今回はこのプログラムを新しくAjax対応させて、OnlyCSViewという名前のWEBサービスにする計画を立てました。

完成までには色々と仕様的な壁にぶち当たりました。その過程をここに順を追って記しておくことで、これからPHPプログラムをAjax対応させようとする方、ならびに自分自身が同じ轍と格闘しないようにしようと思います。

Ajax対応のキモ 〜jQuery.post命令でPHPerにも直感的に

まずは今回のajax対応に関しては、jQueryを使うということに決めました。理由としてライブラリを使わない素のJavaScriptでの開発は、非同期処理実装のためブラウザ毎に異なった命令を使わなければならないということがあり、面倒臭くスマートでないからです。面倒臭いことは時にプログラミングの醍醐味でもあったりしますが、できればメイン部分の処理か、あるいは誰もやらないような事の方に労力をかけたいと思いますよね。
Ajax部分はPHPプログラムで慣れたPOSTを使いたかったので、jQuery.post命令を使います。

jQuery.post(引数1,引数2,引数3,引数4)
引数1 呼び出すurl 今回の例ではcsvtojson.phpという処理部分のファイル
引数2 呼び出し先に与えるデータ。複数の場合はラベルをつける {"label1" : data1,"label2" : data2}
PHP側では$_POST["label1"]のように取り出せる。省略可
引数3 エラーも含め値が帰ってきたら行う処理。省略可
引数4 データの種類。省略可

csvtojson.phpには何を書けば良いでしょうか。PHPのみで作ったCSV表示プログラムの中から、ユーザが指定したCSVファイルが何かを知る機能、と、配列に格納したデータを表に整形する機能、を取り除いて、この2つの機能はJavaScript側で実装するようにします。そうすることで、csvtojson.phpは入力がファイルパス(文字列)、出力が配列という単機能のプログラムにまとまります。
PHPとJavaScriptで配列の受け渡しをするには、JSONというフォーマットを使います。上に書いたjQuery.postの説明の引数2のところで既に出してしまいましたが、何の事はなくJavaScriptのオブジェクトの書式と同じです。ただしラベルは必ず文字列でなければなりません。PHPの配列をJSONにエンコード/デコードする際には、配列をjson_encode関数もしくはjson_decode関数に与えてやるだけで済みます。最後にエンコード済みのJSONフォーマットをechoして、csvtojson.phpの仕事は終わりです。

jQuery.postの方では、引数4に”json”と指定してやる事で、帰ってきたデータをJSONと解釈してくれます。その他にとりうるオプションとして、”xml”,”html”,”script”,”jsonp”,”text”があります。もしCSVの整形表示部までcsvtojson.phpに担当させる設計にするならば、整形後のhtmlを”html”で受けるといった具合です。引数3はfunction(){…と結果が帰ってきた際の処理を匿名関数でそのまま書いてしまえば良く、さらにこの関数の引数として宣言された変数で、帰ってきたデータを受けられます。
実際にjQuery.postでcsvtojson.phpを呼んだ部分はこのようになりました。

jQuery.post("csvtojson.php", {"filepath" : filepath,"charset" : charset},function(data,status){
//処理。変数dataはcsvtojson.phpが返してきた値(JSON)。
//data[i][j]のようにアクセスして値を取り出せる。省略可。
//変数statusには成功、失敗などのステータスが入る。省略可。
},"json");

Ajax対応落とし穴 〜JavaScriptはファイルのローカルパスを知ることができない

メイン処理部分は後回しにして、csvtojson.phpに与えるローカルファイルパス取得の処理を考えます。JavaScriptではWEBページ内のフォームに入力された値を、フォームのname属性で特定して操作する事ができます。したがって、ユーザーに<input type=”file”>でローカルファイルをセットさせて、その値を取り出す。理論的にはそれで大丈夫なはずです。

//HTML部分
<input type="file" name="csvfile" accept="application/excel" />
.
.
.
//JavaScriptでセットされたパスを取得
var filepath = document.controlls.csvfile.value;

ところが、実際にはこの書き方ではパスを取得できません。試しに上のコードに続いてalert(filepath);というコードを実行すると、結果は以下のようになります。

fakepath

fakepathという単語で、実際のファイルパスがマスキングされています。良く言われる、JavaScriptではセキュリティ対策のためローカルファイルにアクセスできないという表現ですが、ファイルへのアクセスにエラーが出るという実装ではなく、そもそもローカルファイルパスを知る事ができないという仕様によるもののようです。したがって、PHPに受け渡してしまえば処理できるというものでもありません。

Ajax対応のキモ 〜HTML5のFile APIを使ってみる

そこで、ローカルファイルアクセスの問題を克服したとこちらも良く言われる、HTML5を使います。HTML4以前で作られたページでHTML5の機能を有効にするには、DOCTYPE宣言をこれまでの複雑なものから、<!DOCTYPE html>というシンプルなものに変えるだけです。詳しい説明はまた別のエントリで行いますね。
HTML5は2014年の正式勧告を目指して仕様策定中という段階であり、API導入の状況は各ブラウザによってまちまちです。今回使用するFile APIは、現時点でFirefoxとChromeが対応、Safariは部分的対応といった状況です。今回のプログラムがFirefoxおよびChromeのみ対応となってしまうのは、このSafari未対応部分の機能を使うからです。
File API対応ブラウザであれば、<input type=”file”>でユーザが選択したファイルに、name属性でなくid属性でアクセスできます。

//HTML部分
<input type="file" id="csvfile" accept="application/excel" />
.
.
.
//JavaScriptでセットされたファイルを変数に代入
var userfile = document.getElementById("csvfile").files[0];
//ファイル名取得
var name = userfile.name;
//サイズ取得
var size = userfile.size;
//タイプ取得
var type = userfile.type;
//urn取得
var urn = userfile.urn;

File APIは複数ファイルの選択にも対応しているため、セットされたファイルはインデクスで指定して取り出します。一つしかセットされていない場合はfiles[0]で指定します。
このurnというプロパティが、いかにもファイルパスだろうという安易な予想をしたのですが、実際ローカルファイルをセットして値を取得してみると空でした。大抵のFile APIの解説でも省略されているのですが、URNというのは、URLと同じくICANNによって唯一性が保証されたファイル名のことで、パスのようにユーザが主体的に値を設定せずとも存在しているものではないようです。いずれは活用するようになるかもしれない名前空間といったところでしょうか。

Ajax対応落とし穴 〜objectURLはセッションを越えられない

File APIにはローカルファイルのパスを知る2通りの方法が用意されています。どちらの方法も発想の逆転で、指定されたローカルファイルに新しくパスを与えるということでセキュリティ上の問題をクリアしています。方法の1つ、objectURLはファイルへの参照を示し、2つ目のDataURLはurl文字列にファイルの内容をそのまま展開してしまいます。もちろんobjectURLの方が圧倒的にバイト数が少ないので、Ajax通信で使うフォーマットとしてはこちらを採用したくなります。

//HTML部分
<input type="file" id="csvfile" accept="application/excel" />
.
.
.
//objectURLを作成
 
//Firefoxの場合
var filepath = window.URL.createObjectURL(document.getElementById("csvfile").files[0]);
//Chromeの場合
var filepath = window.webkitURL.createObjectURL(document.getElementById("csvfile").files[0]);
 
//jQuery.postに与える
jQuery.post("csvtojson.php", {"filepath" : filepath},function(){
//処理
},"json");

しかしながら、こうして作成したObjectURLはセッションを越えられないため、csvtojson.phpはこれを無効なパスと解釈します。残念ではあるのですが、ObjectURLにはまた別のところで活躍してもらうとしましょう。

Ajax対応のキモ 〜filereaderでData URLを作成しパス渡しを実現

Data URLというのは、先程も述べましたがファイル内容をそのまま展開してしまったURLのことで、このURLの解釈自体は大抵のブラウザが対応しています。具体的な採用例としては、Google画像検索で表示される画像がData URLです。File APIのfilereaderではアクセスしたローカルファイルをいくつかのフォーマットに展開することができるのですが、その内の一つのフォーマットがData URLなのです。filereaderの使い方を見てみましょう。

//HTML部分
<input type="file" id="csvfile" accept="application/excel" />
.
.
.
//filereaderインスタンスを作成し、メソッドでファイル読み込み
var reader = new FileReader();
//バイナリ文字列へ
reader.readAsBinaryString(document.getElementById("csvfile").files[0]);
//テキストへ(第二引数は文字コード)
reader.readAsText(document.getElementById("csvfile").files[0],"UTF-8");
//Data URLへ
reader.readAsDataURL(document.getElementById("csvfile").files[0]);
 
//読み込み終了時の処理(非同期なので他のステータスにもメソッドあり)
reader.onload = function(e){
//変数filepathに結果を代入
var filepath = e.target.result;
};

filereaderを使う場合には、FirefoxとChromeの分岐処理は必要ありません。作成されたData URLを、jQuery.postでcsvtojson.phpに送ると正常に処理されました。トラフィックには優しくない方法ですが、とりあえず既存PHPプログラムのAjax対応への糸口が見えました。

$.post("csvtojson.php", {"filepath" : filepath},function(data, textStatus){
var $table = $('<table id="ct"></table>');
for(var i in data){
var $onerow = $("<tr></tr>");
for(var j in data[i]){
$("<td></td>").text(data[i][j]).appendTo($onerow);
}
$onerow.appendTo($table);
}
$("#tablearea").append($table);
},"json");

csvtojson.phpが返してきたJSONをテーブルに整形しています。こちらもjQueryを使って幾分楽をしていますね。

ということで、とりあえず最低限のAjax対応が果たせました。デモはこちらから。
段々肉付けをして便利なサービスにしていきたいと思います。


PHPでシンプルな文字列検索をする

PCREの場合globの場合とPHPのパターン検索方法を挙げましたが、単純に文字列中で特定文字列に完全一致する部分を探すのであれば、strpos関数やstrstr関数を使用すれば事足ります。
strpos関数は文字列中の検索文字列が最初に出現する場所のインデックスを返します。さらに一致する箇所が無い場合にFALSEを返すので、文字列中に検索文字列が存在するか/しないかを調べるPHPの関数も、実はstrposです。

<?php
$string = "abcdefgh";
$search = "def";
if(($pos = strpos($string,$search)) === FALSE){
echo "検索文字列と一致する箇所は無い";
}
else {
echo ($pos + 1)."文字目から一致";
}
?>

引数1が検索対象、引数2が探す文字列、オプションの引数3は探し始める位置です。比較演算子に===を使うのは、FALSE以外のときでも返り値で0を返す可能性があるからですね。なおこのstrposのヴァリエーションとして、大文字小文字の区別をしないstripos、最後に現れる位置を調べるstrrposなどがあります。

strstr関数は、検索文字列以降の文字列を返り値として得る際に使います。

strstr(引数1,引数2,引数3);
引数1,2strposに同じ。
引数3 検索文字列より前の部分を返すフラグ。オプション。

大文字小文字の区別をしないstristrというヴァリエーションもあります。

両方とも使いたいときには名前が出てこない影の薄い関数なので、メモっておきました。


PHPのもう一つのパターンマッチング関数glob

PHP4.3.0以降搭載されているglob関数は、パス文字列を引数に与えることでパターンマッチするパスを探して配列として返してくれる便利な関数です。パターンマッチということで、正規表現のパターンを与えるとマッチングをしてくれるPCRE関数(preg_matchなど)に近いように思われますが、globが解釈するパターンはUNIXシェルのパス名マッチのパターンであり、正規表現より煩雑にならない書き方ができるようです。
たとえば前回preg_grep関数と正規表現を用いて実装した、ディレクトリを検索してその中の拡張子が.jpgのファイルだけ抽出し、セレクトメニューの項目名にするという処理は、globを使うとこのような感じになります。

<?php
$dir = "sample";
$parentlength = strlen($dir) + 1;
echo '<form name="" method="" action=""><select name="">';
foreach(glob($dir."/*.csv") as $val){
echo '<option value="'.htmlentities(substr($val,$parentlength),ENT_QUOTES,"UTF-8").'">'
.htmlentities(substr($val,$parentlength),ENT_QUOTES,"UTF-8").'</option>';
}
echo '</select><input type="submit" value="表示"></form>';
?>

preg_grepでの例の再現のため、項目名としてファイル名のみを取り出そうとしてややこしくなっている部分はありますが、注目すべきはかの例にあったscandir関数のような、ディレクトリ内のパスを取得し配列に納めるというプロセスが省略されているという点です。glob関数はパス検索に特化しており、scandirの直接の上位互換と捉えても良いかもしれません。
さて、関数の説明です。まずパターン文字列の表記方法ですが、PCRE関数のように文字列の前後をスラッシュで囲む必要は無く、パスにワイルドカードなどの特殊記号を交えたものをそのまま与えます。以下が特殊記号です。

記号 意味 使用例 マッチするテキスト
*(アスタリスク) 0文字以上の任意の文字列(ワイルドカード) /home/*/lib /home/userA/lib,home/userB/lib
?(クエスチョンマーク) 任意の1文字 /img/img???.jpg /img/img001.jpg,/img/img002.jpg
¥(円マーク) 特殊文字のエスケープ(windows) /post.php¥?* /post.php?post=””
\(バックスラッシュ) 特殊文字のエスケープ(windows以外) /post.php\?* /post.php?post=””
[](角括弧) 括弧内に現れる文字のどれか /te[xs]t.php /text.php,/test.php
-(ハイフン)を使った応用編 /te[a-z]t.php /tebt.php,/tewt.php(aからzまで可)
-(ハイフン)を使った応用編 /te[1-9]t.php /te3t.php,/te8t.php(1から9まで可)
!(エクスクラメーション)は角括弧中で否定の意 /te[!nx]t.php /test.php(text,tentはダメ)

正規表現と細かな違いがありますね。アスタリスクがワイルドカードの役割をするという辺りは、CSSやSQLの熟練者にはわかり易くて良いのではないでしょうか。
書式と定数の説明です。

glob(引数1,引数2);
引数1 : パターン文字列
引数2 : オプションフラグ。省略可。以下の定数をとり得る。
GLOB_MARK ディレクトリがマッチした場合最後にセパレータのスラッシュを付加
GLOB_NOSORT 結果として返す配列をソートしない(デフォルトはソート)
GLOB_NOCHECK マッチする結果が無かった場合、検索パターン自体を返す
GLOB_NOESCAPE エスケープ文字(¥,\)を機能させない
GLOB_BRACE {パターン1,パターン2,パターン3}という指定で複数パターンの検索をする
GLOB_ONLYDIR マッチしたディレクトリのみを返す
GLOB_ERR エラー時に停止する(PHP5.1.0以降)

正規表現における|(パイプライン)でのOR検索は、引数にGLOB_BRACEを与えた上で{}(中括弧)で括って行う必要があります。

preg_grepを使った例では、読み込んだファイル名を一旦ユーザインターフェースに出力しユーザに選ばせるという、完全にリモートのWEBサービスを意識した構成でした。それに対してglobの強みが生きてくるのは、ディレクトリに追加されたファイルを強制的に全部読み込んで表示するといった、ユーザの了解を省略したローカルディレクトリベースのアプリケーションなのかもしれません。


PHPのPCRE関数を使ってデイレクトリ内の特定拡張子ファイルのリストを取得する

前回解説した正規表現とPCRE関数を使って、ディレクトリ内の特定の拡張子のファイルのリストを作成してみます。今回のサンプルプログラムではさらに、特定の拡張子のファイルリストを得た後それをhtmlのselect要素に整形することで、ユーザにファイルを選ばせて処理を加えるWEBアプリケーションのインターフェース部分という体裁で書いてみようと思います。

<?php
$dir = "sample";
echo '<form name="" method="" action=""><select name="">';
foreach(preg_grep("/\.jpg$/",scandir($dir)) as $val){
echo '<option value="'.htmlentities($val,ENT_QUOTES,"UTF-8").'">'
.htmlentities($val,ENT_QUOTES,"UTF-8").'</option>';
}
echo '</select></form>';
?>

ディレクトリを検索してその中の拡張子が.jpgのファイルだけ抽出し、セレクトメニューの項目名にしています。ここで使っている関数は、引数2に配列を与えると引数1に与えた正規表現文字列にマッチする要素だけを配列に格納し、返り値として返すpreg_grepという関数です。

preg_grep(引数1,引数2,引数3);
引数1 : 正規表現文字列(前後にスラッシュで囲む)
引数2 : 抽出元の配列
引数3 : 反転フラグ。PREG_GREP_INVERTを与えると、条件にマッチしない要素の配列を返す。省略可。

例では引数2にscandir関数を与えて、ディレクトリ内の全てのファイル/ディレクトリ名を配列にしています。その中からの拡張子.jpgの抽出を、preg_grep関数が担当するようになっています。
この例ではあまり問題になりませんが、preg_grep関数には気をつけなければならない点が一点あります。返り値として返す配列の添字が、引数に与えた元の配列のものを継承するということです。つまり配列の添字が必ずしも連番になっていないので、添字をカウントアップさせて要素をひとつずつ取り出すループとは上手く連携できません。そうした処理と連携する場合は、array_values関数を使って配列の要素に連番の添字をアサインし直しましょう。


PHPで正規表現による文字列のパターンマッチングを行う

文字列の中の特定のパターンを検索する方法として、正規表現というものがあります。以前、.htaccessでディレクトリ内の特定文字列を含むファイルへのアクセスを禁止する方法について書いたエントリの中で少し触れたのですが、今回は書式のおさらいと、PHPでの対応する関数の紹介を行います。

まず正規表現の書式ですが、以前紹介したエスケープ(\または¥)、行頭(^)、行末($)、または(|)の他にもいくつか記号があるので、一覧表にしてみます。

記号 意味 使用例 マッチするテキスト
.(ピリオド) 任意の一文字(ワイルドカード) te.t text,tent,te!t
*(アスタリスク) 直前の文字の0回以上の繰り返し te.*t text,texxxt,tet
+(プラス) 直前の文字の1回以上の繰り返し te.+t text,texxxt
?(クエスチョンマーク) 直前の文字が0または1回登場 te.?t text,tet
¥(円マーク) 特殊文字のエスケープ(windows) te¥.¥?t te.?t
\(バックスラッシュ) 特殊文字のエスケープ(windows以外) te\.\?t te.?t
^(カレット) 行頭 ^\.ht .htaccess,.htpasswd
$(ドル) 行末 nt$ tent,plant
[](角括弧) 括弧内に現れる文字のどれか te[xyz]t text,tezt
-(ハイフン)を使った応用編 te[a-z]t tebt,tewt(aからzまで可)
-(ハイフン)を使った応用編 te[1-9]t te3t,te8t(1から9まで可)
^(カレット)は角括弧中で否定の意 te[^nx]t test(text,tentはダメ)
()(丸括弧) グルーピング (te)*xt xt,text,tetext
|(パイプライン) または ([a-z]|[1-9])* aaa,a,9999

PHPで正規表現によるマッチングを行うには、PCRE関数というPerlでの正規表現に準拠した関数群を使います。preg_という接頭辞がついたこの関数群に正規表現のパターンを与える時は、パターン文字列の前後をスラッシュで囲むという約束事があります。基本的なpreg_match関数で例を見てみましょう。

<?php
$teststring = "Hello!";
preg_match("/He[a-z]+/",$teststring);
?>

引数1にパターン文字列、引数2に検索対象を与えています。引数3、4、5もあるのですが、省略可です。 パターン文字列にマッチしたものがあると、preg_match関数は返り値として1を返します。ちなみに返り値として検索がマッチした回数を返してくれる、preg_match_allという関数もあります。
その他、検索置換機能を備えたpreg_replaceや、配列を精査してくれるpreg_grepという関数もありますので、それらの活用例もいずれエントリでアップできればと思っています。


サイトC:000webhostで頻発するwordpressアップデートエラーを回避する

このサイトで契約しているサーバ000webhostですが、無料であることに加え、MySQLのデータベースを2つ使える、設定パネルとしてcPanelの簡易版が使える、広告が入らない、商用可などのメリットがあり、他と比べてもかなり条件の良いサーバであると個人的に思っています。特にMySQLデータベースが2つまで使えるということは、データベースをまるまる1つ占有してしまうwordpressなどのCMSを気兼ねなく導入できるということで、CMSの実験用として契約するユーザも多数存在するのではないかと予想できます。

一見するとCMSとの相性が良さそうに見えるこのレンタルサーバでは、しかしCMS自体の機能を使ったアップデートやプラグインの導入などの際に、エラーが発生してしまうということが多々あります。加えて、ユーザのアップロードが成功せず何回もトライを続けていると、負荷の低減のためかあるいは不正使用と誤認してなのか判りませんが、当該IPアドレスでのアクセスをしばらく禁止されてしまいます。それにより総合的なユーザエクスペリエンスが最低となり、実験用に契約した場合でも、「このサーバは使えない」という結論に繋がってしまう可能性があります。
そこで、そもそもこういった負の連鎖の原因となるアップロード失敗の原因を突き止め、問題を回避する方法を考えましょう。
結論から言いますと、アップデート時のエラーが頻発するのはサーバ側でPHPプログラムの動作を制限して軽い処理しかできないようにしているためで、000webhostのように.htaccessが使える場合、あるいは他の安サーバでもphp.iniが使える場合、それらの設定を変更することでエラー回避の道が開ける場合もあるというのは知っておいて損のない知識です。具体的に000webhostの場合で見てみましょう。

まずはphpinfo関数でphpの設定を調べて下さい。エラーに関係する項目のみ挙げますが、000webhostの場合デフォルトでmax_execution_timeが10、memory_limitが64M、post_max_sizeが2M、upload_max_filesizeが2Mとなっています。それぞれPHPスクリプトがタイムアウトになるまでの秒数、確保するメモリ容量、POSTで渡せる最大ファイルサイズ、アップロードできる最大ファイルサイズを表しています。
参考までに、サイトAのために契約しているWebhostingPadではこの値が30、128M、8M、2Mになっています。つまり000webhostではこれらの値を厳し目に設定することで、無料ユーザを総合した負荷を抑えるようにしているというわけのようです。
これらの変更を、ユーザのルートディレクトリに置く.htaccessで行いましょう。具体的には、max_execution_timeを少し長めの180秒程度にする、postやuploadのmaxサイズをmemoryリミットの制限内で上げるなどです。.htaccessまたはphp.iniでどのように書けばよいかは、少し前に上げたエントリ(php.ini.htaccess)を参考にして下さい。あまり詳しく言及すると000webhostの勘気に触れるのではないかという個人的な危惧があります(笑)

少しの欠点がありますが、対処を覚えれば便利なサーバーですね。いちユーザの意見としてポジティブに評価しておきましょう。

(2012.6追記:勝手にページを非公開にされ、コンテンツの返還に有料契約を要求された事件があり、現在このサーバは他人にお薦めしません。少し詳しい経緯などはこちら