GDで透過ありインデックスカラー画像を合成すると

前回エントリではインデックスカラー画像の合成を試みました。サンプルプログラムのように周囲に余白が無い画像の場合には期待通りの合成ができるのですが、たとえばimagerotate関数で45度傾けた長方形の場合などには、合成する画像の周囲の余白を透明部分として処理する方法が無く暗幕を被せたようになってしまいます。これは前回も触れたとおりです。
ではGDライブラリがインデックスカラーの透過色に全く対応していないかというと、そういうことでもないようです。画像編集ソフトで透過色ありの設定で保存したPNGを読み込むと、それはそのまま透過色ありの画像として扱われ、他の画像に合成しても透過の設定は残ります。例で見てみましょう。

<?php
$img = imagecreate(200,200);
$colour1 = imagecolorallocate($img, 255, 0, 255);
$colour2 = imagecolorallocate($img, 100, 90, 100);
imagefilledrectangle($img, 0, 160, 200, 200, $colour2);
$img2 = imagecreate(200,20);
$colour4 = imagecolorallocate($img2, 255, 255, 255);
$img3 = imagecreatefrompng("test.png");
$img4 = imagerotate($img4,90,$colour4,0);
imagecopy($img,$img4,10,0,0,0,150,200);
header('Content-Type: image/png');
imagepng($img);
imagedestroy($img);
imagedestroy($img2);
imagedestroy($img3);
imagedestroy($img4);
?>

前回とほとんど変わらないプログラムです。新しく出てきた関数imagecreatefrompngはPNG画像を読み込んだキャンバスを作成するもので、他にimagecreategifなどもあるというのはご想像のとおりです。引数に同ディレクトリ内の透過色ありPNGを指定したのですが、結果このように表示されました。

(この部分の画像は000webhostに接収されてしまいました)

判りにくいのですが、元の透過PNGの透過設定が保持され、合成先画像のピンクの背景を突き抜けて透過しています。傾いた長方形の周囲の白い部分は、黒字の背景のページに設置すると黒になります。つまり合成先画像のカラーパレットと、透過色設定を含んだ合成元画像のカラーパレットを単純に結合したためこういう事態になっているということのようです。ちなみにimagerotate関数の引数4を0以外にしても見え方は変わりませんでした。
こうした仕様もあり、GDで複数の画像を合成して画像を作成する場合には、フルカラー画像を前提にしてプログラムを書いた方が予期せぬ壁に阻まれることがないだろう、という教訓も得られようというものです。


GDライブラリを用いてWEB表示用の画像を生成する

htmlコーダからのステップアップでPHPを習得したばかりという人間。クラスを活用したプログラムを書くのはまだ敷居が高いけれど、htmlをパッチワークのように切り貼りして作る練習ばかりではつまらない。そんな状況の人間には、GDライブラリを使ったグラフィックの生成にチャレンジすることをお勧めします。
何がそれほどまでにお勧めなのかというと、まず大抵のレンタルサーバにインストールされていて、ファイルの追加インストールの必要がないということ。includeする必要も無いので、サーバのphpパッケージのディレクトリパスも知っている必要がありません。そして重要なポイントとして、imgタグのsrc属性に指定したときに××.phpという指定が残るので、htmlの知識しか無い人間を当惑させることができるということ。少しだけ優越感に浸れて、PHPを勉強して良かったと思えるかもしれません。

<?php
$img = imagecreate(200,200);
$colour1 = imagecolorallocate($img, 255, 0, 255);
$colour2 = imagecolorallocate($img, 100, 90, 100);
imagefilledrectangle($img, 0, 160, 200, 200, $colour2);
$img2 = imagecreate(200,20);
$colour3 = imagecolorallocate($img2, 0, 0, 0);
$colour4 = imagecolorallocate($img2, 255, 255, 255);
$img3 = imagerotate($img2,90,$colour4,0);
imagecopy($img,$img3,10,0,0,0,20,200);
header('Content-Type: image/png');
imagepng($img);
imagedestroy($img);
imagedestroy($img2);
imagedestroy($img3);
?>

基本的にはこのような流れで画像を作っていきます。細部の説明をしましょう。

まずimagecreate関数ですが、引数に画像サイズ(x,y)を与えて、画像を一時的に保存するメモリを確保する関数です。画像を描くキャンバスをサイズを決めて用意するというイメージで理解するのが良いかもしれません。インデックスカラー画像を作成する場合にこのimagecreate関数を使い、16ビットフルカラー画像の作成の場合にはimagecreatetruecolorという関数を使います。インデックスカラーとフルカラーの違いについてはこちらのエントリを参考にして下さい。

次にimagecolorallocate関数ですが、imagecreate関数で確保したメモリ領域(変数$imgで参照してます)を引数1に、その後の3つの引数はそれぞれ赤、緑、青を0〜255までの256段階で表し、混色しています。
さて、インデックスカラーでは使用する色は必ずカラーパレットで宣言されていなければいけないということを思い出して下さい。そうした仕様のため、imagecreate関数でメモリを確保したあと、最初に呼び出されたimagecolorallocate関数の色は、優先的に背景色としてアサインされます。勿論返り値を格納した変数は、キャンバス上に別の図形を描く際に呼び出して使うことも可能です。

さて、その次のimagefilledrectangle関数では、長方形を描画しています。引数はキャンバス、長方形の左上のx,y座標、右下のx,y座標、塗りつぶしの色という順番です。

下って出てくるimagerotateという関数は、引数1に与えたキャンバスを、反時計回りに引数2の角度回転させたものを返すという関数です。この例では90度回転なのでうまく余白部分が無しになっていますが、引数3にはキャンバスを回転させた余白部分の色、引数4には透過色を無視するかどうか(0以外の値で無視。デフォルトは0。省略可)を与えます。ちなみにこの引数4の設定は残念ながらインデックスカラーのキャンバスに定義した図形には適用できないので(透明色定義のimagecolortransparentが、フルカラーのキャンバスにしか対応していない)、ここでは無視して構いません。

imagecopy関数の引数は、コピー先キャンバス、コピー元キャンバス、コピー先x,y座標(左上)、コピー元x,y座標(左上)、コピー元x,y座標(右下)という順番です。コピー元x,y座標の指定次第で、部分コピーも可能です。

header関数では出力イメージのcontent-typeを指定して下さい。imagepng関数はPNG出力を、imagegif関数ならGIF出力をします。最後にimagedestroy関数で確保したメモリの解放をして終了します。出力されたイメージを見てみましょう。

(この部分のイメージは000webhostによって接収されてしまいました)

ピンク色の背景色にimagefilledrectangleで描いた灰色の長方形が置かれ、その上にimagecopyで合成された回転後の長方形が置かれていますね。

これでファイル名は××.phpながらイメージとしてコピー/ダウンロードできる画像が出来上がります。GDではさらに複雑な画像生成もできるので、プログラマ心を程よく刺激してくれる筈でしょう。


フォーム入力のサニタイジングを行う(PHP編)

ユーザの入力をフォームで受け付けWEBページに出力する処理を含んだプログラムでは、入力値のサニタイジング(無害化)が必要です。WEBブラウザは表示内容にhtmlタグが含まれているとこれを自動的に解釈して反映してしまうため、悪意あるユーザがタグを混入させた入力を行えば、表示出力段階で設計者の想定外の処理が行われてしまうからです。
実例を見てみましょう。たとえば以下のような簡単なプログラムがあったとします。

<html>
<head>
<title>sample.php</title>
</head>
<body>
<?php
echo $_POST["userin"];
?>
フォームへの入力値を表示する
<form action="sample.php" method="post">
<input type="text" name="userin"></input>
<input type="submit" value="送信"></input>
</form>
</body>
</html>

このプログラムのユーザ入力に、<h1>このページの内容は嘘八百である</h1>というタグ付きテキストを渡してみます。するとh1タグが解釈され、目立って大きなテキストとして表示されてしまいます。たとえば掲示板プログラムなど、ユーザ入力が残り続けるページの場合にはこの「このページの内容は嘘八百である」という文言が残り続け、h1タグが付いているため検索エンジンにもこれがページの主要内容と誤解されてしまいます。さらに掲示板の背景色と同じ文字色をタグで指定すれば、管理者にも容易に気付かれずこの文言が残り続けることになります。

また、タグが解釈されてしまうということはscriptタグに挟んだ任意のスクリプトも実行できてしまうということです。ユーザの情報をクッキーに保存しているサイトで、<script>alert(document.cookie);</script>と入力すれば、scriptタグ中のjavascriptが処理され、クッキーに保存されたユーザ情報にアクセスできてしまいます。
この脆弱性と、アドレスにフォームへの入力内容を付加できるという特性を利用して行われるのがXSS(クロスサイトスクリプティング)です。この場合攻撃者(Aとします)は攻撃対象サイト(B)のアドレスにフォーム入力内容を加えたリンクを、悪意の無いユーザ(C)に踏ませます。クッキーに格納されたユーザ(C)の情報はスクリプトにより攻撃者(A)に取得され、たとえばそれがパスワードであった場合には不正アクセスが可能になってしまいます。さらにクッキーに保存された情報の種類によっては、もっと深刻な個人情報の漏洩にもなり得ます。

このような攻撃への対策として行われるのがサニタイジングです。htmlタグを示す<や>といった文字をエスケープして他の文字列を充てるという処理で、PHPにはそれを行う関数が幾つか存在します。以下それらの関数個別の説明を行います。

strip_tags関数

この関数はその名の通り、htmlとPHPのタグを文字列から取り除きます。また2番目の引数として特定のタグを与えることで、そのタグは取り除かないといった指定もできます。一見便利そうですが、タグであるとの判定が<と>に囲まれているということなので、ユーザ入力として閉じてないタグ(例:<script)を与えられると、遥か先に存在する>を探し出してそこまでの文字列を全て取り除いてしまうという可能性があり諸刃の剣です。

addslashes関数

この関数がエスケープするのはタグを構成する文字ではなく、シングルクォート、ダブルクォート、スラッシュといったデータベース操作のSQL文を構成する要素です。これはSQLインジェクションという攻撃への対策であり、このエントリの内容からは外れるのですが、ここで言及するのはこの機能をデフォルトでオンにしているレンタルサーバが多いからです。
正確にはPHP設定のmagic_quotes_gpcという項目名のもので、これがonになっていると自動的にフォーム入力値にaddslashes関数が実行されるというものです。先程のフォーム入力表示プログラムにエスケープ対象になる文字列を入力して、バックスラッシュや¥マークが付加されて表示される場合はこれが有効になっています。ある意味この自動エスケープも入力内容の予期せぬ改変を引き起こすと言えなくもなく、またSQLインジェクションへの対策という点から見てもこの機能は不完全ですので、PHPの最新ヴァージョンでmagic_quote_gpcが廃止されるなどの動きもあるようです。この辺りの話はまたSQLインジェクションについてのエントリを立てて説明します。

htmlspecialchars関数

この関数は、htmlタグを構成する<と>、&、設定によってはシングルクォートとダブルクォート、以上の5種類に対しエスケープを行ってくれる関数です。&に何故エスケープが必要かというと、この文字はエスケープ変換後の文字列の先頭に現れエスケープの表明になるからです。たとえば<をエスケープすると&lt;という文字列になります。シングルクォート、ダブルクォートについても、CSSでの値指定で使われる文字で、これを利用した攻撃方法が存在するのでエスケープの必要があります。デフォルトではダブルクォートのみエスケープという指定になっているので、この関数を利用する際には引数を与えシングルクォートのエスケープも有効にしなければなりません。以下は書式です。

htmlspecialchars(引数1,引数2,引数3);
/*
引数1:変換対象文字列
引数2:(省略可)クォートの扱い。0〜3の整数値または定数で指定。
定数ENT_QUOTESを与えると両方変換する。
引数3:(省略可)文字コード。UTF-8など明示的に指定しておいた方が良い。
*/

この関数を常に使うのが有効な対策です。

htmlentities関数

htmlspecialchars関数と同じく文字列を&lt;のようにエスケープしてくれるのですが、対象文字がエスケープ可能な全ての文字にわたります。ウムラウト付き文字やギリシャ文字、記号類が主な対象です。全てのリストは、htmlの特殊文字などで検索して調べて下さい。
この関数をhtmlspecialchars関数の代わりに使うこともできます。ただやはりクォートのエスケープのデフォルト値はダブルクォートのみなので、第二引数にENT_QUOTESを与えて下さい。

ユーザからの入力を表示するプログラムにサニタイジングが必要ということは、前回作成したようなファイルアップロードを受け付けるプログラムでも適切なエスケープが必要になります。ファイルから読み込んで表示する部分にエスケープするのは勿論ですが、$_FILES変数の$_FILES[][‘type’]、$_FILES[][‘name’]などについても、ユーザが任意の値を設定できるため、エスケープするべきです。

以上がPHPでのサニタイジングです。サニタイジング以外にも、ファイル構成や入力チェックなどでセキュリティを上げることが可能ですので、その方面での対策と常にセットで考えておきましょう。


fgetcsvで読み込んだCSVファイルをhtmlのテーブルとして出力

タイトルどおり、fgetcsv関数で読み込んだCSVファイルをテーブルにします。
PHPの動くサーバに設置してローカルのファイルを求める仕様です。サニタイジングを省略しているので公開領域には置かないでください。

csvtotable.php
 
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<h2>テーブル表示するcsvファイルを指定して下さい。</h2>
<form enctype="multipart/form-data" action="csvtotable.php" method="POST" />
<input type="file" name="csvfile" accept="application/excel" />
<input type="submit" value="送信" />
</form>
<br />
<?php
if(isset($_FILES["csvfile"])){
if($fp = fopen($_FILES["csvfile"]["tmp_name"],r)){
echo '<table border = "1">';
while(($row = fgetcsv($fp)) != false){
echo "<tr>";
for($i = 0; $i < count($row); $i++){
echo "<td>" . mb_convert_encoding($row[$i],"UTF8","SJIS-win") . "</td>" ;
}
echo"</tr>";
}
echo "</table>";
}
}
?>
</body>
</html>

エクセルで作成されたShift-JISのCSVファイルを読み込むという設定で、fgetcsvで読み込んだ値をいちいちmb_convert_encoding関数でShift-JISからUTF-8に変換して表示しています。この関数は引数1に変換対象の文字列、引数2に変換後エンコーディング、引数3に変換元エンコーディングを与えるのですが、変換元としてただのShift-JISを与えたケースでは、”かっこかぶ”やローマ数字などが表示できませんでした。SJIS-winと指定するのが正解なようです。
なお、このプログラムで上手く表示できない場合は前回説明したような問題が発生している可能性もあります。記事を参考にしてあたりをつけてみて下さい。


PHPでCSVファイルの読み込み/書き出しをする

表計算ソフトやデータベースなどのデータの受け渡しに使うフォーマットとして、CSVというフォーマットがあります。このフォーマットはCSV(Comma-Separated Values)の名前のとおり、複数の値をカンマで区切っただけのテキストファイルで、書式さえ理解していれば特別なソフトを使わずに作成や修正をすることができるので便利です。今回はこのフォーマットの書式の説明と、PHPで読み込んで配列に格納または出力する関数の紹介をします。

CSVの書式

CSVでは値の区切りをカンマで、データ行の区切りを改行コードで行います。たとえば表計算ソフトで以下のような表があったとします。

世界ランキング 名前 コメント
1 みかん 「次も頑張ります」
2 りんご 「妥当な結果です」
3 メロン 「スタートに失敗した。このまま腐ってしまっては仕方が無い」

この表をCSVファイルとして出力すると、次のようなテキストファイルが生成されるはずです。

世界ランキング,名前,コメント
1,みかん,「次も頑張ります」
2,りんご,「妥当な結果です」
3,メロン,「スタートに失敗した。このまま腐ってしまっては仕方が無い」

値の区切りがカンマで示され、行の区切りが改行で示されているのがわかります。値は”みかん”のように、ダブルクォーテーションで囲んでも構いません。ですが、注意すべきケースが3つ程存在します。

  1. 値がカンマを含んでいるケース
  2. 先述の通りカンマは値同士の区切りとして特別な意味を持ちますので、値自体にカンマが含まれている場合、それが区切り文字でないことを明示しなければなりません。そこで先程値を囲むのに使ってもよいと書いたダブルクォーテーションで、カンマを含んだシーケンスを挟んでそれが一つの値であると明示するのに使います。たとえば「スタートに失敗した,このまま腐ってしまっては仕方が無い」という値を、次のように囲みます。

    3,メロン,"「スタートに失敗した,このまま腐ってしまっては仕方が無い」"
    
  3. 値が改行を含んでいるケース
  4. 値が改行を含んでいる場合にも、それが列の区切りではないと明示しなければなりません。この場合もダブルクォーテーションで囲むという方法が使えます。
    「スタートに失敗した。
    このまま腐ってしまっては仕方が無い」
    という値の表記例を見てみましょう。

    3,メロン,"「スタートに失敗した。
    このまま腐ってしまっては仕方が無い」"
    
  5. 値がダブルクォーテーションを含んでいるケース
  6. 値にダブルクォーテーションが含まれている場合には、それが値の一部であって表記規則の一部でないことを明示しなければなりません。そのためにはまず値全体をダブルクォーテーションで括り、さらに値中のダブルクォーテーションは2つ重ねることによって間違って解釈されることを回避します。”スタートに失敗した。このまま腐ってしまっては仕方が無い”という値は、以下のように表記します。

    3,メロン,"""スタートに失敗した。このまま腐ってしまっては仕方が無い"""
    

    なぜダブルクォーテーションが3つ連続しているのかは、順序立てて考えると分かり易いです。大切な規則は、ダブルクォーテーションを使う場合かならず値の一番外側はダブルクォーテーションで囲まなければならないということです。

以上が基本的なCSVの書式になりますが、ソフトによって方言や独自の拡張文法も存在しています。が、国際標準として成文化されたルールは上記のものになりますので、データの広い受け渡しを想定するならばこのルールに倣っておきましょう。

PHPでのCSVファイルの取り扱い

PHPでは、CSVファイルを読み込んで二次元配列に格納する関数fgetcsvがヴァージョン4から、二次元配列をCSVのフォーマットに整形してファイルに書き込むfputcsvがヴァージョン5.1から存在しています。それぞれの書式は以下のようになります。

fgetcsv(引数1,引数2,引数3,引数4,引数5);
/*ここからコメント
引数1はfopenなどで取得したファイルポインタ。
引数2以降は省略可能。
引数2 = 行の最大長
引数3 = 値の区切り文字(デフォルトはカンマ)
引数4 = 値の囲い文字(デフォルトはダブルクォーテーション)
引数5 = エスケープ文字(デフォルトはバックスラッシュ)
*/
fputcsv(引数1,引数2,引数3,引数4);
/*
引数1 = ファイルポインタ
引数2 = 値の二次元配列
以下省略可
引数3 = 値の区切り文字(デフォルトはカンマ)
引数4 = 値の囲い文字(デフォルトはダブルクォーテーション)
*/

ただしfgetcsvの方は、値が日本語のときに上手く読み込めないという事例がネット上でも多数報告されています。どうもExcelなどのCSVの作成元が日本語文字コードにShift-JISを採用していて、PHPでユーザが設定している文字コードがEUC-JPまたはUTF-8という状況でのエラーが多いようです。さらに調べると、fgetcsv関数は文字コードの処理時に、default_charsetではなくPHPのロケール設定という利用者の地域設定を参照するようで、setlocaleという関数を使って地域と使用文字コードを明示的に設定してやらなければならないようです。

setlocale(LC_ALL, "ja_JP.UTF-8");
/*
setlocale関数の書式
setlocale(引数1,引数2);
引数1 = ロケール設定が適用される関数のカテゴリ。
とりあえずLC_ALLを指定すると適用できる全ての関数に有効になる。
引数2 = ロケール名
ja_JPまでがロケール名だが、ドットの後ろに文字コードまで指定できる。
*/

このsetlocale関数を用いて、Shift-JISのCSVファイルをUTF-8環境に読み込み表示するプログラムを個人的に実行してみました。が、結果として当方の環境ではやはり文字化けが起こってしまいました。したがって、当面の対策としては、エラーを避けるためにCSVファイルの方を整形してからプログラムに読み込ませるという方法を採用しています。具体的には、値をダブルクォーテーションで必ず囲むようにする、CSVファイルの文字コードをPHPでのエンコーディングに変換して保存し直すなどです。
CSVでのデータ受け渡しができることには計り知れないメリットがあるので、この問題が早々に解決してくれることを期待します。


サイトC:PHPの各種設定をphp.iniではなく.htaccessで行う

以前php.iniを使ったPHPの各種設定変更方法を書きました。しかしながら、レンタルサーバによってはユーザがphp.iniファイルを作成する事を許可してない場合があります。当方の場合、まさにサイトC(このサイト)を設置している000webhostがそうだったのですが、そういったケースではphp.iniファイルを使わず.htaccessファイルで設定の変更を行います。
.htaccessでPHPの設定を変更する場合、変更する値のタイプによって書き方が2種類存在します。具体的には、論理値を指定する場合に使うphp_flagと、それ以外の値を指定する場合に使うphp_valueです。そこで実際サイトCにおいて私が行った設定を例にしながら、2種類の書式を見てみましょう。

論理値を指定するタイプ

論理値を指定する場合というのは、PHPのオプション機能の有効/無効を指定する場合で、書式は次のようになります。

php_flag 設定項目 On
php_flag 設定項目 Off

繰り返しになりますが、文の最後には改行が必要です。実例として、PHPプログラムでエラーが発生した際の、エラーメッセージをブラウザに出力する設定をアクティブにしてみます。

php_flag display_errors On

このオプションが有効になっていると、実行したプログラムの何行目でどのようなエラーが起こったかを親切に表示してくれます。もちろんサイト訪問者側からもエラー内容が見えてしまうことになるので、必要の無いときにはOffを指定しておきましょう。

他の値(文字列、数値)を指定するタイプ

文字列や数値を指定する場合には、以下の書式を使います。

php_value 設定項目 設定内容

実例としてはphp.iniの解説で挙げたデフォルト文字コードの指定があります。これは.htaccessで設定する場合以下のようになります。

php_value default_charset UTF-8

UTF-8の部分をダブルクォーテーションで囲んでも適用されるようです。
数値の例としては、処理がタイムアウトになるまでの秒数であるmax_execution_timeを挙げます。

php_value max_execution_time 60

その他の設定項目も、この2種類の書式で指定することができます。どのような項目があるかはphpinfo()やPHPパッケージ付属のphp.iniで知ることができます。ただしレンタルサーバによっては特定の項目のユーザー側からの変更をブロックしている場合がありますので、そういう場合についてはあきらめて別の方法を模索しましょう。


サイトB:MAMPの導入と複数サイト運用のための設定

MacOSX上のローカル環境につくる予定のサイトBですが、ローカル環境の構築にはMAMPというアプリケーションを使用します。このMAMPというアプリケーションはOSに影響を与えることなくApache、MySQL、PHPのテスト環境を提供するソフトウェアで、windows用のソフトウェアとして有名なXAMPPと同等のものです。現在ではXAMPPがOSX、Linuxにも対応していますが、MAMPの場合はMacOS用のリリースを以前から行っていたため、OSXの仮想環境ソフトウェアとしてユーザーが多くリファレンスも充実しています。

早速導入をしてみましょう。MAMPのトップページの左側のDownload nowボタンをクリックすると、最新版のダウンロードが始まります。右側で紹介されているMAMP PROは60ドル程度の有料版で、こちらは複数サイトの運営が標準機能として搭載されています。その他にも機能差が存在するのですが、無料版の方もいわゆる機能限定デモのような圧倒的に痒いところに手が届かないという体ではないので安心して使えます。
以前のMAMPは解凍したアプリケーションを手動でアプリケーションフォルダに移す必要がありましたが、現在の最新ヴァージョンではインストーラ形式になっています。便利な反面、販促の為か標準インストールで勝手にMAMP PROまでインストールする仕様になっています。不要ならばカスタムインストールのオプションでMAMP PROのチェックボックスを外しましょう。
インストールが終わったら、アプリケーションフォルダに作成されたMAMPのフォルダを開きMAMPアプリケーションを立ち上げます。

(この部分の画像は000webhostに接収されました)

この画面が出たら正常に起動しています。左下のウインドウにはサーバのステータスが表示されます。また、環境設定のボタンから各種設定をすることができます。

さて、デフォルトの状態でのドキュメントルートは、MAMPフォルダの一階層下のhtdocsフォルダになっています。このままですとサイトを一つしかテストできないので、サイトを複数作成・テストする場合にはhtdocsフォルダの下にフォルダを作成して、そこをドキュメントルートとみなしファイル構成を行います。

(この部分の画像は000webhostに接収されました)

ここではフォルダeをドキュメントルートとしたサイトと、フォルダlをドキュメントルートとしたサイトの2サイトの運用を想定します。フォルダ構成が済んだら、先程の環境設定ボタンで現れるフローティングウィンドウのApacheタブを選択して下さい。そこに記載されたパスがサイトのドキュメントルートになるので、それぞれチェックするサイトのルートフォルダを指定し、その都度MAMPを再起動して下さい。指定したフォルダに、MAMP起動時に現れるページの、アドレス後半部の/MAMP/?language=Japaneseを削ったアドレスでアクセスできるようになります。

(この部分の画像は000webhostに接収されました)

設定を変更後再起動という面倒臭さはあるものの、一応これで複数サイトの運営が可能になります。公開しないローカル環境であることの強みを生かして、実験的なサイトをいくつも作ってしまいましょう。