nodistでNode.jsをVersion管理する(Windows)
nodistのインストール
nodistはNode.jsをVersion管理できるツール
nodistのインストーラを以下よりダウンロードする
github.com
現時点の最新であるv0.8.8を選択しダウンロードしインストールする
今回は特に初期設定のまま変更せずにインストールした
コマンドプロンプトを開き、node -v を実行しインストールしたVersionが表示されればOK
nodistの使い方
nodistのアップデート
nodistのアップデートを実行、更新があればアップデートされる
C:\WINDOWS\system32>nodist selfupdate
現在取得したNode.jsのVesionと指定しているVersionの確認
現在取得したNode.jsのVesionと指定しているVersionの確認
以下はv9.5.0が指定されていることがわかる
C:\WINDOWS\system32>nodist (x64) 8.8.1 8.9.4 > 9.5.0 (global: 9.5.0)
nodistでインストール可能なNode.jsのバージョンを表示
nodistでインストール可能なNode.jsのバージョンを表示
C:\WINDOWS\system32>nodist dist : 9.3.0 9.4.0 9.5.0
nodistでVesionを指定しNode.jsをインストール
nodistで例えばv9.3.0を指定しNode.jsをインストールする
C:\WINDOWS\system32>nodist + v9.3.0 9.3.0 [===============] 21825/21825 KiB 100% 0.0s 9.3.0
nodistでNode.jsのバージョンを切り替え
nodistでNode.jsをv9.3.0に切り替える
C:\WINDOWS\system32>nodist 9.3.0 9.3.0 Default global pacakge update dsuccessful.
Node.jaのVersionが切り替わらない場合
今回、nodistでNode.jsのインストールはうまくいくけど、
Node.jsのVersion切り替えに失敗するという現象に陥った。。
調べていると、元々Node.jsをインストールしていた後にnodistをインストールすると、
うまく切り替えられないみたい。
その場合は、もともと入っているNode.jsをアンインストールすればOK
郵便番号検索 Webアプリを作る(2)
郵便番号検索 Webアプリを作る(1)の続き
ソースコードの各処理の内容をみていく
HTML Head
<meta charset=" ">
について、「charset属性」は、HTML5から単独で使えるようになった属性
文字コードは、「Shift_JIS」「UTF-8」などがありますが、HTML5から、UTF-8 を使用することが推奨されている
理由はWin、Mac、Linux、Unix、どんな OSでもOKなのと、
2バイト文字(漢字や仮名などの日本語・中国語・ハングル・アラビア語など)も含めた、世界中の言語の文字を表示できるから
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
でbootstrapのCSSを指定し読み込む
<style type="text/css">
以降で、HTML文書にCSSを適用する
<head> <meta charset="UTF-8"> <title>郵便番号検索</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> <style type="text/css"> .container { text-align: center; margin-top: 100px; width: 450px; } .result { margin-top: 20px; } </style> </head>
HTML Body
Bootstrapで基本的なformを作るために
<div class="form-group">
や
<input type~ class="form-control"
を指定し、レイアウトを利用する
<div class="container"> <h1>郵便番号検索</h1> <div class="form-group"> <label for="exampleInputText">住所を入力してください</label> <input type="text" id="city" class="form-control" placeholder="ex. 大阪府大阪市北区小松原町"> </div> <button class="btn btn-primary" id="btn">検索</button> <div class="result" id="str"></div> </div>
Google Maps Geocoding API
検索ボタンが押下されたら、
入力された住所の郵便番号を取得する処理を行う
郵便番号の取得には、Google Maps Geocoding API を利用する。
事前準備として以下サイトでAPI Keyを取得する。
developers.google.com
キーの取得のページに遷移する
API Keyを取得したらメモする
次に住所から郵便番号を取得するために以下のAPIを使う
https://maps.googleapis.com/maps/api/geocode/json?address=[住所]&key=[取得したAPI Key]
例えば、住所に「千代田区千代田」を入れてAPIを実行
[https://maps.googleapis.com/maps/api/geocode/json?address=千代田区千代田&key=[取得したAPI Key]
結果として以下のJSONが取得できる
{ "results" : [ { "address_components" : [ { "long_name" : "千代田", "short_name" : "千代田", "types" : [ "political", "sublocality", "sublocality_level_2" ] }, { "long_name" : "1", "short_name" : "1", "types" : [ "political", "sublocality", "sublocality_level_4" ] }, { "long_name" : "千代田区", "short_name" : "千代田区", "types" : [ "locality", "political" ] }, { "long_name" : "東京都", "short_name" : "東京都", "types" : [ "administrative_area_level_1", "political" ] }, { "long_name" : "日本", "short_name" : "JP", "types" : [ "country", "political" ] }, { "long_name" : "100-0001", "short_name" : "100-0001", "types" : [ "postal_code" ] } ], "formatted_address" : "日本、〒100-0001 東京都千代田区千代田1", "geometry" : { "bounds" : { "northeast" : { "lat" : 35.6905143, "lng" : 139.7614146 }, "southwest" : { "lat" : 35.6773769, "lng" : 139.7443137 } }, "location" : { "lat" : 35.6838012, "lng" : 139.7539454 }, "location_type" : "APPROXIMATE", "viewport" : { "northeast" : { "lat" : 35.6905143, "lng" : 139.7614146 }, "southwest" : { "lat" : 35.6773769, "lng" : 139.7443137 } } }, "place_id" : "ChIJ4bzvNguMGGARUXRpAo8Oi6s", "types" : [ "political", "sublocality", "sublocality_level_2" ] } ], "status" : "OK" }
取得した値のそれぞれの値はデベロッパー ガイドを参考にすればよいが、
今回は郵便番号なので、"postal_code"を利用する
入力された住所から郵便番号を取得し結果を表示する
jQueryのAJAXメソッドを使って「Google Maps Geocoding API」をよびだすので、
jQueryのライブラリを読み込む
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
以下で検索ボタンがクリックされたときのイベント処理を実装する
<script type="application/javascript"> var postalCode = ""; var btn = document.getElementById('btn'); btn.addEventListener('click', function() {
住所が入力されていなければalert()で警告表示し結果表示部分にも、
「郵便番号が見つかりません。」という文言を表示する。
その際、Bootstrapのalertsのレイアウトを使って表示する
Alerts · Bootstrap
var city = document.getElementById('city'); if (city.value == "") { alert("住所を入力してください"); document.getElementById("str").innerHTML = "<div class=\"alert alert-primary\" role=\"alert\">郵便番号が見つかりません。</div>";
Google Maps Geocoding APIの第1引数 addressに入力された住所、第2引数に取得したAPI Keyを指定し、
ajaxメソッドを利用してAPIをよび出す
APIの呼び出しが成功すれば、
$.each()をつかい、取得したデータにpostal_codeがないか?検索する
postal_codeがあれば、郵便番号を表示する
} else { const API_KEY = xxxxxxxxxxx; //個人のAPI key var url = "https://maps.googleapis.com/maps/api/geocode/json?address=" + city.value + "&key=" + API_KEY; $.ajax({ url: url, type: "GET", success: function(data) { postalCode = ""; $.each(data['results'][0]['address_components'], function(key, value) { if (value["types"][0] == "postal_code") { postalCode = value["long_name"]; } }) if (postalCode) { document.getElementById("str").innerHTML = "<div class=\"alert alert-primary\" role=\"alert\">郵便番号は、" + postalCode + "です。</div>"; } else { document.getElementById("str").innerHTML = "<div class=\"alert alert-primary\" role=\"alert\">郵便番号が見つかりません。</div>"; } } }) } }) </script>
※$.each() は配列やハッシュに対して繰り返し処理を行うことができる
$.each() は以下のように記述する。
$.each(対象のオブジェクト, function(index, val) { 繰り返し実行する処理 });)
配列 array に対して繰り返し処理を行う場合は、以下のように記載する。
array = ["Apple", "Orange", "Grape"]; $.each(array, function(index, val) { $('ul').append("<li>" + index + ":" + val + "</li>"); });
郵便番号検索 Webアプリを作る(1)
初めてのWebアプリを作ってみる。
ということで、住所を入力すれば郵便番号を表示するアプリを作成する
以下イメージです。
住所を入力を入力すると、郵便番号を表示してくれる簡単なWebアプリ。
開発技術
HTML + JavaScript で実装
郵便番号の取得は、Google Maps Geocoding API をjQueryで呼び出す
デザインはBootStrapを活用
ソースコード
先にソースコードを記載する。
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>郵便番号検索</title> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous"> <style type="text/css"> .container { text-align: center; margin-top: 100px; width: 450px; } .result { margin-top: 20px; } </style> </head> <body> <div class="container"> <h1>郵便番号検索</h1> <div class="form-group"> <label for="exampleInputText">住所を入力してください</label> <input type="text" id="city" class="form-control" placeholder="ex. 大阪府大阪市北区小松原町"> </div> <button class="btn btn-primary" id="btn">検索</button> <div class="result" id="str"></div> </div> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <script type="application/javascript"> var postalCode = ""; var btn = document.getElementById('btn'); btn.addEventListener('click', function() { var city = document.getElementById('city'); if (city.value == "") { alert("住所を入力してください"); document.getElementById("str").innerHTML = "<div class=\"alert alert-primary\" role=\"alert\">郵便番号が見つかりません。</div>"; } else { const API_KEY = xxxxxxxxxxx; //個人のAPI key var url = "https://maps.googleapis.com/maps/api/geocode/json?address=" + city.value + "&key=" + API_KEY; $.ajax({ url: url, type: "GET", success: function(data) { //console.log(data); postalCode = ""; $.each(data['results'][0]['address_components'], function(key, value) { if (value["types"][0] == "postal_code") { postalCode = value["long_name"]; } }) if (postalCode) { document.getElementById("str").innerHTML = "<div class=\"alert alert-primary\" role=\"alert\">郵便番号は、" + postalCode + "です。</div>"; } else { document.getElementById("str").innerHTML = "<div class=\"alert alert-primary\" role=\"alert\">郵便番号が見つかりません。</div>"; } } }) } }) </script> </body> </html>
内容の詳細は次回に記載する。
PHPで天気情報APIのOpenWeatherMapを使う
ユーザが都市名を入力すると天気情報APIのOpenWeatherMapを使い、
現在の天気を表示するWebアプリをPHPで作成する。
はじめに
天気情報を取得するためにOpenWeatherMapのAPIを利用するが、
利用するにはユーザ登録が必要。
OpenWeatherMapにアクセスし、ユーザー登録を行う
openweathermap.org
コード
先にコードを記載する。
<?php $weather = ""; if (array_key_exists('city', $_GET)) { $urlContents = file_get_contents("http://api.openweathermap.org/data/2.5/weather?q=".$_GET['city']."&appid=XXXXXXXXXXXXXXXXXXXXXXXXX"); //appidにはAPI Keyを入れる $weatherArray = json_decode($urlContents, true); //連想配列の場合は第2引数へtrueを指定 //print_r($weatherArray); $weather = $_GET['city']."'s Weather:".$weatherArray['weather'][0]['main'].",".$weatherArray['weather'][0]['description']; } ?> <h1>What's The Weather?</h1> <form> <label for="city">Enter the name of a city.</label> <input type="text" class="form-control" name="city" id="city" placeholder="Eg. London, Tokyo" value="<?php if (array_key_exists('city', $_GET)) { echo $_GET['city']; }?>"> <button type="submit" class="btn btn-primary">Submit</button> </form> <?php if ($weather) { echo '<div class="alert alert-success" role="alert">'.$weather.'</div>'; } ?>
天気情報APIのOpenWeatherMapを使う
今回は簡単に実装するため、file_get_contents()にAPIを渡す
appidにはユーザ登録で取得したAPI Keyを渡す
※file_get_contents()にAPIを渡す場合、
タイムアウトが設定通り動かない、リクエストが失敗した場合は、過去の成功したヘッダ情報を返してしまう
などの問題があるので注意が必要。
$urlContents = file_get_contents("http://api.openweathermap.org/data/2.5/weather?q=".$_GET['city']."&appid=XXXXXXXXXXXXXXXXXXXXXXXXX");
次に返ってきたJSONをjson_decode()を使い配列に入れてユーザに通知する。
$weatherArray = json_decode($urlContents, true);
今回は現在の天気とその詳細を表示するだけですが、
返ってきたJSONの中に最高/最低気温や湿度などの情報もある
また5日間の天気予報情報を取得できるAPIもあるので、色々と使ってみたい。
PHP+MySQLで簡単なログインフォームを作成する
ログインフォームにメールアドレスとパスワードを入力して、
登録ボタンを押下するとMySQLのDBにデータが登録される簡単なWebアプリ
開発言語:PHP
環境:MAMP(Apache + MySQL)
MySQLのデータベースを追加する
phpMyAdminにアクセスする
以下にデータベース名を入力して[作成]ボタンを押下する
作成したデータベースにテーブルを追加する
今回はusersというテーブル名でカラムはEmail、Password、Nameとするので3を入力します。
次に挿入タブから3つほどデータを追加しておく
今回は以下のデータを用意した
ソースコード
先にソースコードを以下に記載する
<?php // データーベースへ接続 $link = mysqli_connect("localhost","root","root","MemberApp"); // 接続に失敗すれば強制終了 if(mysqli_connect_error()){ die("Failed Connect DB."); } //データが入力されているかどうかチェックする if(array_key_exists('email',$_POST) OR array_key_exists('password', $_POST)) { if($_POST['email'] == ''){ echo "Emailアドレスを入力してください"; } elseif($_POST['password']==''){ echo "Passwordを入力してください"; } else{ //メールアドレスが既に使用されていないかチェックする $query = "SELECT `id` FROM `users` WHERE email = '".mysqli_real_escape_string($link,$_POST['email'])."'"; $result = mysqli_query($link,$query); if(mysqli_num_rows($result) > 0){ echo "既にそのメールアドレスは使用されています。"; }else{ //未使用の場合、データベースに登録する $query = "INSERT INTO `users` (`email`,`password`) VALUES('" .mysqli_real_escape_string($link,$_POST['email']) ."','" .mysqli_real_escape_string($link,$_POST['password']) ."')"; if(mysqli_query($link,$query)){ echo "登録が成功しました。"; } else{ echo "登録が失敗しました"; } } } } ?> <!DOCTYPE html> <form method="post"> <input type="text" name="email" placeholder="Email"> <input type="password" name="password" placeholder="password"> <input type="submit" value="登録する"> </form>
データーベースへ接続
mysqli_connect()を使ってデータベースへ接続
$link = mysqli_connect("localhost","root","root","MemberApp");
第1引数はMySQL サーバーのホスト名もしくはIPアドレス
第2引数はMySQLのユーザー名
第3引数はMySQLのパスワード
第4引数はクエリが行われるデフォルトのデータベース
詳細は以下
PHP: mysqli::__construct - Manual
mysqli_connect_error() で""以外が返ってきた場合、
接続に失敗したとみなし、die()で強制終了する
if(mysqli_connect_error()){ die("Failed Connect DB."); }
データが入力されているかどうかチェックする
array_key_exists()でPOSTで受け取ったデータに
'email'もしくは'password'が入っていなければ、エラー表示を行う。
if(array_key_exists('email',$_POST) OR array_key_exists('password', $_POST)) { if($_POST['email'] == ''){ echo "Emailアドレスを入力してください"; } elseif($_POST['password']==''){ echo "Passwordを入力してください"; }
メールアドレスが既に使用されていないかチェックする
初めに作成したusersテーブルからSELECT文を使い、
入力されたemailがデータベースに登録済みかどうか判定する
//メールアドレスが既に使用されていないかチェックする
$query = "SELECT `id` FROM `users` WHERE email = '".mysqli_real_escape_string($link,$_POST['email'])."'";
$result = mysqli_query($link,$query);
if(mysqli_num_rows($result) > 0){
echo "既にそのメールアドレスは使用されています。";
}else{
mysqli_query()でデータベース上でクエリを実行する。
第1引数は、mysqli_connect() で取得したリンクID
第2引数は実行するクエリ、今回はSELECT文
PHP: mysqli::query - Manual
mysqli_real_escape_string()は、
接続の現在の文字セットを考慮して、SQL 文で使用する文字列の 特殊文字をエスケープする 関数
例えば名前に'が入っている場合は、そのまま渡すとクエリの実行に失敗するので、
この関数で特殊文字をエスケープしておく
mysqli_num_rows()で取得した結果が何個あるか?を取得する。
今回は入力したemailとデータベースに登録されているemailが一致しなければ、
未登録のemailと判断して次に進む
データベースに登録する
INSERT文で入力されたemailとpasswordをデータベースへ登録する。
mysqli_query()が成功すれば登録されたと判断し echo でその旨ユーザに通知する
$query = "INSERT INTO `users` (`email`,`password`) VALUES('" .mysqli_real_escape_string($link,$_POST['email']) ."','" .mysqli_real_escape_string($link,$_POST['password']) ."')"; if(mysqli_query($link,$query)){ echo "登録が成功しました。"; } else{ echo "登録が失敗しました";
OpenCVでヒストグラム計算する
以下のように、Webカメラで取得した画像にヒストグラムのグラフを重ねて表示するアプリを作成する。
開発環境の構築は以下参照。
OS:Windows
言語:C++
IDE:Visual Stdio2015
robinit.hatenablog.com
ヒストグラムとは??
画像処理の分野では、各濃度値に対してその濃度値を持った画素数を求めたもので、
濃度ヒストグラムまたは単純にヒストグラムという。
詳細は以下参照
http://izumi-math.jp/sanae/inf_box/histgram/histgram.htm
カメラ画像取得
VideoCapture cap(0) でカメラをオープン。引数の"0"はデフォルトのカメラを意味する。
2台目のカメラを接続しオープンする場合は、"1"を指定する。
VideoCapture::isOpened() でカメラがオープンされたかチェック
cap >> frame で現在のフレームをcv::Matに取得。
VideoCapture cap(0); // デフォルトカメラをオープン if (!cap.isOpened()) // 成功したかどうかをチェック return -1; do { cap >> frame; // カメラから新しいフレームを取得 } while (frame.empty());
グレースケール化
ヒストグラムの計算に使用する画像はグレイスケール化が必要
OpenCVの cv::cvtColor を利用してグレースケール化する
Mat gray; cvtColor(frame, gray, CV_BGR2GRAY);
ヒストグラム計算
以下のようにOpenCVの cv::calcHist を利用してヒストグラムを求め、
ヒストグラムのグラフ画像を作成する
// ヒストグラムを描画する画像割り当て const int ch_width = 256, ch_height = 128; Mat hist_img(Size(ch_width, ch_height), CV_8UC3, Scalar::all(255)); const int hdims[] = { 256 }; // 次元毎のヒストグラムサイズ const float hranges[] = { 0,256 }; const float* ranges[] = { hranges }; // 次元毎のビンの下限上限 double max_val = .0; // シングルチャンネルのヒストグラム計算 // 画像(複数可),画像枚数,計算するチャンネル,マスク,ヒストグラム(出力), // ヒストグラムの次元,ヒストグラムビンの下限上限 calcHist(&gray, 1, 0, Mat(), hist, 1, hdims, ranges); // 最大値の計算 minMaxLoc(hist, 0, &max_val); // ヒストグラムのスケーリング hist = hist * (max_val ? ch_height / max_val : 0.); for (int j = 0; j < hdims[0]; ++j) { int bin_w = saturate_cast<int>((double)ch_width / hdims[0]); rectangle(hist_img, Point(j * bin_w, hist_img.rows), Point((j + 1) * bin_w, hist_img.rows - saturate_cast<int>(hist.at<float>(j))), Scalar::all(128),-1); } // ヒストグラム画像のROI表示重ね合わせ Mat roi_img(targetImg, Rect(20, targetImg.rows - hist_img.rows - 20, ch_width, ch_height)); hist_img.copyTo(roi_img);
サンプル実装
以下サンプル実装
#include "opencv2/opencv.hpp" using namespace cv; /* ヒストグラムを計算し、ヒストグラムのグラフを描画する 第一引数: gray ヒストグラムを計算するグレイスケール画像 (in) 第二引数: targetImg グラフを重畳する画像 (inout) 第三引数: hist ヒストグラムの計算結果 (out) */ void drawHist(const Mat& gray, Mat& targetImg, Mat& hist) { // ヒストグラムを描画する画像割り当て const int ch_width = 256, ch_height = 128; Mat hist_img(Size(ch_width, ch_height), CV_8UC3, Scalar::all(255)); const int hdims[] = { 256 }; // 次元毎のヒストグラムサイズ const float hranges[] = { 0,256 }; const float* ranges[] = { hranges }; // 次元毎のビンの下限上限 double max_val = .0; // シングルチャンネルのヒストグラム計算 // 画像(複数可),画像枚数,計算するチャンネル,マスク,ヒストグラム(出力), // ヒストグラムの次元,ヒストグラムビンの下限上限 calcHist(&gray, 1, 0, Mat(), hist, 1, hdims, ranges); // 最大値の計算 minMaxLoc(hist, 0, &max_val); // ヒストグラムのスケーリング hist = hist * (max_val ? ch_height / max_val : 0.); for (int j = 0; j < hdims[0]; ++j) { int bin_w = saturate_cast<int>((double)ch_width / hdims[0]); rectangle(hist_img, Point(j * bin_w, hist_img.rows), Point((j + 1) * bin_w, hist_img.rows - saturate_cast<int>(hist.at<float>(j))), Scalar::all(128), -1); } // ヒストグラム画像のROI表示重ね合わせ Mat roi_img(targetImg, Rect(20, targetImg.rows - hist_img.rows - 20, ch_width, ch_height)); hist_img.copyTo(roi_img); } int main() { VideoCapture cap(0); // デフォルトカメラをオープン if (!cap.isOpened()) // 成功したかどうかをチェック return -1; Mat frame; while (1) { do { cap >> frame; // カメラから新しいフレームを取得 } while (frame.empty()); // frame画像対象の処理 // グレースケール画像に変換 Mat gray; cvtColor(frame, gray, CV_BGR2GRAY); // ヒストグラム計算 Mat hist; drawHist(gray, frame, hist); imshow("CatImg", frame); int keyVal = waitKey(30); if (keyVal == 27) { // Escキー break; } } return 0; }
PHP 基礎2
GETメソッドの引数を受け取る方法
例えば、URLに以下のような引数をセットしGETメソッドを発行する。
http://localhost:8080/index.php?name=kawa&gender=man&kimi=sugoi
? 以降が、引数になる。&で各引数をで区切って記述する。
PHPでGETの引数を利用する方法は以下のように記述する。
<?php print_r($_GET); //引数すべてを標準出力 echo $_GET['name']; echo $_GET['gender']; ?>
例えば、フォームから引数を設定する場合、以下のように記述する。
<?php print_r($_GET); echo $_GET['name']; echo $_GET['gender']; ?> <form> <input type="text" name="name"> <input type="checkbox" name="gender" value="man">man <input type="checkbox" name="gender" value="woman">woman <input type="submit" value="send"> </form>
POSTメソッドの引数を受け取る方法
POSTメソッドの引数を受け取るサンプル実装
ユーザが名前を入力すれば、”Hello 名前” という文字が表示される。
<?php if($_POST){ echo "Hello ".$_POST['name']; } ?> <form method="post"> <input type="text" name="name"> <input type="submit" value="send"> </form>
Emailを送信する方法
mail()メソッドを利用してメールを送信する
mail()メソッドの詳細は以下参照。
PHP: mail - Manual
サンプル実装は以下のとおり。
<?php $emaitTo = "test@test.com"; $subject = "Test Subject"; $body = "Test Body"; $headers = ""; if(mail($emailTo, $subject, $body, $headers)){ echo "Email Success"; } else { echo "Email Faild"; } ?>
実行して以下のようなエラーが発生した場合、
送信元メールアドレスのFromが指定していないことが原因。
php.ini の
; For Win32 only.
;sendmail_from = me@example.com
の部分を、
; For Win32 only.
sendmail_from = 利用するメールアドレス
に更新すること。