手把手教你在SAE上打造自己的免费天气预报应用
最近开始学习PHP语言,本着理论联系实际的原则,边学边做个小项目。也没什么好的想法,于是就继续做天气预报吧。没钱租空间,而Google App Engine使用起来在国内有些限制(比如需要“翻土啬”才能打开应用主页),所以暂时放弃。而新浪云(以下简称SAE)当前正火,使用门槛较低,实名认证后可以免费使用很长时间,就它了!
大家可以先看一下应用完成后的样子。网址http://zhitianqi.sinaapp.com,猛击此处进入。
这是我刚刚做好的一个天气应用,这个应用有一个简单的主页,打开后根据IP地址显示当前所在城市的天气预报,包含当天天气详情以及常用的几个生活指数。在该页面还可以手动更换城市,以及订阅免费的天气预报短信。当然这里订阅的实际上是“邮件”,只不过使用手机邮箱(移动139邮箱,联通手机邮箱或者电信189邮箱)订阅的话,邮箱收到天气预报时,会给手机发送短信提醒,进而实现了短信天气预报。
OK,接一下咱一步一步实现这个天气应用。(SAE的注册与认证很简单,这里就不说了)
第一步:创建一个新的应用
点击页面最上边的“我的应用”,打开应用列表,这里会显示所有你创建的应用。
再点击“创建新应用”,打开创建新应用页面。
这里我们选择创建空应用,然后按要求填表。这里注意3个地方:二级域名也就是AppID,开发语言以及应用类型。二级域名不能重复,本来想用tianqi的,不过已经被人注册了,我就写tianqi123,这同时也是我们这个应用的应用ID。这个ID决定了将来应用主页网址就是http://tianqi123.sinaapp.com。开发语言选择PHP,应用类型选择Web应用。然后点击创建应用。
这时候会弹出“安全认证”窗口,注意此处要的是安全密码而不是登录密码!
经过安全验证后,一个SAE应用就创建成功了。接下来就要准备代码了。
第二步:安装TortoiseSVN并进行代码检出
TortoiseSVN下载地址:http://tortoisesvn.net/downloads.html,有两个版本,根据你的系统选择32位或64位版本,不要选错了。下载安装之后,点击右键发现多了TortoiseSVN的菜单。点击SVN Checkout,进行代码检出。注意每次修改代码前都要进行代码检出。
点击确定后,等到提示Competed At revision: 0(以后每次检出成功这个数字都会加1)时,就完成了代码检出。此时在所选文件夹下(此处是E:\blog)就多了一个tianqi123的文件夹,这个文件夹图标上还有一个绿色的对号。
进入这个文件夹,然后在里面新建一个文件夹,名称为数字1(SAE应用版本号只能是1~10的整数数字)。
第三步:开始编写代码吧
打开1文件夹,新建一个名为index.php的文件,这个文件就是应用主页。打开index.php文件,把以下代码复制进去,然后保存。
<?php
require_once('func.php');
require_once('get_guest_info.php');
$query_string = $_SERVER["QUERY_STRING"];
//处理POST请求
if ($_POST) {
$w_info = get_weather_by_name($_POST['city']);
} elseif (preg_match('/^c=(\d{9})$/', $query_string, $matches)) {
$city_code = $matches[1];
$w_info = get_weather_by_code($city_code);
} else {
// 根据IP地址显示当地天气
$gifo = new get_guest_info();
$address = $gifo->Getaddress_2();
$reg_addr = '/((.+)省|*|内蒙古|宁夏|广西|*)?(.*)市/';
preg_match($reg_addr, $address['country'], $matches);
$prov = $matches[2] ? $matches[2] : $matches[1]; //得到省份名称
$city = $matches[3]; //得到城市名称
$w_info = get_weather_by_name($city);
}
$title = $w_info['city'] . '天气预报';
$cityid = $w_info['cityid'];
$poster = "http://poster.weather.com.cn/p_files/base/" . $cityid . ".jpg";
$date = $w_info['date_y'];
$release_time = $date . $w_info['fchh'] . '时发布';
$tempreture = array(
$w_info['temp1'],
$w_info['temp2'],
$w_info['temp3'],
$w_info['temp4'],
$w_info['temp5']
);
$weather = array(
$w_info['weather1'],
$w_info['weather2'],
$w_info['weather3'],
$w_info['weather4'],
$w_info['weather5']
);
$wind = array(
$w_info['wind1'],
$w_info['wind2'],
$w_info['wind3'],
$w_info['wind4'],
$w_info['wind5']
);
$day_image = array(
$w_info['img1'],
$w_info['img3'],
$w_info['img5'],
$w_info['img7'],
$w_info['img9']
);
$night_image = array(
$w_info['img2'],
$w_info['img4'],
$w_info['img6'],
$w_info['img8'],
$w_info['img10']
);
for ($i = 0; $i < 5; $i++) {
$day_image[$i] = sprintf('%02s', $day_image[$i]);
$night_image[$i] = sprintf('%02s', $night_image[$i]);
if ($night_image[$i] == '99') {
$night_image[$i] = $day_image[$i];
}
}
$reg_date = '/(\d+)年(\d+)月(\d+)日/';
preg_match($reg_date, $date, $matches);
$today = mktime(0, 0, 0, $matches[2], $matches[3], $matches[1]);
$days = array(
$today,
strtotime('+1 day', $today),
strtotime('+2 day', $today),
strtotime('+3 day', $today),
strtotime('+4 day', $today)
);
$index_cy = $w_info['index_d']; //穿衣指数
$index_uv = $w_info['index_uv']; //紫外线指数
$index_cl = $w_info['index_cl']; //晨练指数
$index_ag = $w_info['index_ag']; //过敏指数
$index_xc = $w_info['index_xc']; //洗车指数
$index_tr = $w_info['index_tr']; //旅游指数
$index_co = $w_info['index_co']; //舒适度指数
$index_ls = $w_info['index_ls']; //晾晒指数
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title><?php
echo '我的天气预报 - ' . $title;
?></title>
</head>
<body>
<?php echo '<h1>' . $title . '</h1>'; ?>
<form method="post" action="">
<input type="text" name="city" style="border: 1px solid #ccc;" size="13" />
<input type="hidden" name="action" value="change_city" />
<input type="submit" value="更换城市" class="button" />
</form>
<hr />
<h3>今日天气</h3>
<?php
printf('<img src="%s" alt="%s" /><br />', $poster, $city);
printf('今天是<b>%s</b>,<b>%s</b>,天气<b>%s</b>,气温<b>%s</b>,
<b>%s</b><br />', $date, get_week($today), $weather[0], $tempreture[0], $wind[0]);
echo '<b>紫外线指数:</b>' . $index_uv . '<br />';
echo '<b>舒适度指数:</b>' . $index_co . '<br />';
echo '<b>晨 练指数:</b>' . $index_cl . '<br />';
echo '<b>晾 晒指数:</b>' . $index_ls . '<br />';
echo '<b>过 敏指数:</b>' . $index_ag . '<br />';
echo '<b>旅 游指数:</b>' . $index_tr . '<br />';
echo '<b>穿 衣指数:</b>' . $index_cy . '<br />';
?>
<hr />
<h3>
未来4日天气情况
</h3>
<!--表格-->
<table class="weather">
<tr>
<?php
$dd = array(
'今天',
'明天',
'后天'
);
for ($i = 1; $i < 3; $i++) {
echo '<th>';
printf('%s(%s)', get_week($days[$i]), $dd[$i]);
echo '</th>';
}
for (; $i < 5; $i++) {
echo '<th>';
printf('%s(%s)', get_week($days[$i]), date('j日', $days[$i]));
echo '</th>';
}
?>
</tr>
<tr>
<?php
for ($i = 1; $i < 5; $i++) {
if ($i <> 4) {
echo '<td>';
} else {
echo '<td style="border: 0;">';
}
printf('<img src="http://wap.weather.com.cn/m/i/icon_weather/21x15/d%s.gif" /><img src="http://wap.weather.com.cn/m/i/icon_weather/21x15/n%s.gif" /><br />', $day_image[$i], $night_image[$i]);
printf('<b>%s</b><br />%s<br />%s', $tempreture[$i], $weather[$i], $wind[$i]);
echo '</td>';
}
?>
</tr>
</table>
<hr />
<h3>免费订阅天气预报</h3>
<p>仅需3步,获得早晚短信天气预报,而且是<b>免费</b>的哟!</p>
<ol>
<li>开通<b>免费的</b><a href="http://mail.10086.cn/" target="_blank">移动139邮箱</a>或者
<a href="http://mail.wo.com.cn/" target="_blank">联通手机邮箱</a>或者
<a href="http://mail.189.cn/" target="_blank">电信189邮箱</a>;
</li>
<li>设置邮件提醒方式为<b>长短信</b>;</li>
<li>留下您的邮箱和城市,天气预报将以短信方式发至您的手机,早晚各一次。</li>
</ol>
<!--Subscribe form-->
<form method="post" id="customForm" action="result.php">
<table>
<tr>
<th><label for="email">邮箱</label></th>
<td><input id="email" name="email" type="text" /></td>
<td><span id="emailInfo">请留下您的邮箱地址吧!</span></td>
</tr>
<tr>
<th><label for="city">城市</label></th>
<td><input id="city" name="city" type="text" /></td>
<td><span id="cityInfo">您想关注哪个城市的天气?</span></td>
</tr>
<tr>
<th> </th>
<td><div class="QapTcha"></div></td>
</tr>
<tr>
<th> </th>
<td><input type="submit" name="sub" value="订阅" class="button" /></td>
</tr>
<input type="hidden" name="action" value="subscribe" />
</table>
</form>
<hr />
<h3>友情链接</h3>
<script type="text/javascript"><!--
google_ad_client = "ca-pub-8820899098050798";
/* 大尺寸横版 链接单元 728 x 15 */
google_ad_slot = "4864840936";
google_ad_width = 728;
google_ad_height = 15;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
<a href="http://think3t.iteye.com" style="margin-left: 10px;font-size: 14px;line-height: 16px;">► 三思之旅</a>
<a href="http://zhitianqi.sinaapp.com" style="margin-left: 30px;font-size: 14px;line-height: 16px;">► 知天气</a>
<hr />
<h3>站内统计</h3>
<?php
$counter = new SaeCounter();
$counter->create('guest', 0);
if ($counter->exists('guest')) {
$counter->incr('guest');
} else {
$counter->create('guest', 0);
$counter->incr('guest');
}
$guest_num = $counter->get('guest');
echo '<div style="margin-left: 4px;">';
printf('当前有<b style="color: red;"> %s </b>位用户访问本站<br />', $guest_num);
printf('其中有<b style="color: red;"> %s </b>位用户订阅天气', get_user_num());
echo '</div>';
?>
<div id="footer">2013 Powered by <a href="http://think3t.iteye.com/">三思之旅</a></div>
</body>
</html>
接下来再新建一个名为func.php的文件,复制以下内容并保存。这个文件是获取天气信息、获取城市代码等函数的代码。
<?php
require_once('db-config.php');
function get_city_code($city_name = '北京')
{
$remote_server = 'http://search.weather.com.cn/wap/search.php';
$post_data = array(
'city' => $city_name,
'submit' => 'submit'
);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $remote_server);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($post_data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($ch);
curl_close($ch);
//Post的返回结果如下:
//<script>window.location="http://wap.weather.com.cn/wap/weather/101010100.shtml";</script>
$data = explode("/", $data); //$data[5]='101010100.shtml";<';
$data = explode('.', $data[5]);
return $data[0];
}
function get_weather_by_name($city_name = '北京')
{
$city_code = get_city_code($city_name);
$weatherurl = "http://m.weather.com.cn/data/" . $city_code . ".html";
$weatherjson = file_get_contents($weatherurl);
$weatherarray = json_decode($weatherjson, true);
$weatherinfo = $weatherarray['weatherinfo'];
return $weatherinfo;
}
function get_weather_by_code($city_code = '101010100')
{
$weatherurl = "http://m.weather.com.cn/data/" . $city_code . ".html";
$weatherjson = file_get_contents($weatherurl);
$weatherarray = json_decode($weatherjson, true);
$weatherinfo = $weatherarray['weatherinfo'];
return $weatherinfo;
}
function get_weather_sms_by_code($city_code = '101010100')
{
$w_info = get_weather_by_code($city_code);
$title = $w_info['city'] . '天气';
$date = $w_info['date_y'];
$tempreture = array(
$w_info['temp1'],
$w_info['temp2'],
$w_info['temp3']
);
$weather = array(
$w_info['weather1'],
$w_info['weather2'],
$w_info['weather3']
);
$wind = array(
$w_info['wind1'],
$w_info['wind2'],
$w_info['wind3']
);
$reg_date = '/(\d+)年(\d+)月(\d+)日/';
preg_match($reg_date, $date, $matches);
$today = mktime(0, 0, 0, $matches[2], $matches[3], $matches[1]);
$days = array(
$today,
strtotime('+1 day', $today),
strtotime('+2 day', $today),
strtotime('+3 day', $today)
);
for ($i = 0; $i < 3; $i++) {
$days_string[$i] = date('j日', $days[$i]) . '[' . get_week($days[$i], true) . ']';
}
$weather_sms = array(
$title,
$days_string,
$weather,
$tempreture,
$wind
);
return $weather_sms;
}
function get_week($day, $short = false)
{
$week_short = array(
'周日',
'周一',
'周二',
'周三',
'周四',
'周五',
'周六'
);
$week = array(
'星期日',
'星期一',
'星期二',
'星期三',
'星期四',
'星期五',
'星期六'
);
$w = date('w', $day);
if ($short)
return $week_short[$w];
else
return $week[$w];
}
function init_db()
{
$conn = @mysql_connect(DB_HOST_M, DB_USER, DB_PASSWORD) or die('数据库连接失败:' . mysql_error());
if ($conn) {
//选择数据库
mysql_select_db(DB_NAME, $conn);
$sql = 'CREATE TABLE subscriber
(
ID int NOT NULL AUTO_INCREMENT,
PRIMARY KEY(ID),
Mail varchar(30),
CityName varchar(20),
CityCode varchar(9)
)';
mysql_query($sql, $conn);
}
mysql_close($conn);
}
function add_user($mail, $city_name)
{
$city_code = get_city_code($city_name);
$conn = @mysql_connect(DB_HOST_M, DB_USER, DB_PASSWORD) or die('数据库连接失败:' . mysql_error());
if ($conn) {
mysql_select_db(DB_NAME, $conn);
$sql = "INSERT INTO subscriber (Mail, CityName, CityCode) VALUES ('$mail', '$city_name', '$city_code')";
//$sql = "INSERT INTO subscriber (Mail, CityName, CityCode) VALUES ('aaa@qq.com', '宜阳', '123456789')";
@mysql_query($sql, $conn) or die('数据库插入失败:' . mysql_error());
}
mysql_close($conn);
}
function get_user_num()
{
$conn = @mysql_connect(DB_HOST_M, DB_USER, DB_PASSWORD) or die('数据库连接失败:' . mysql_error());
if ($conn) {
mysql_select_db(DB_NAME, $conn);
$sql = "SELECT * FROM subscriber";
$result = @mysql_query($sql, $conn) or die(mysql_error());
mysql_close($conn);
return mysql_numrows($result);
}
}
function send_weather()
{
$conn = @mysql_connect(DB_HOST_M, DB_USER, DB_PASSWORD) or die('数据库连接失败:' . mysql_error());
if ($conn) {
mysql_select_db(DB_NAME, $conn);
$sql = "SELECT Mail, CityCode FROM subscriber";
$result = @mysql_query($sql, $conn) or die(mysql_error());
$city_list = array();
while ($row = mysql_fetch_assoc($result)) {
$city_list[$row['CityCode']] .= $row['Mail'] . ',';
}
$mail = new SaeMail();
foreach ($city_list as $city => $mails) {
$w_info = get_weather_sms_by_code($city);
$to = trim($mails, ',');
$sub = $w_info[0];
$msg = '';
for ($i = 0; $i < 3; $i++) {
$msg .= sprintf('%s:%s,%s,%s。%s', $w_info[1][$i], $w_info[2][$i], $w_info[3][$i], $w_info[4][$i], PHP_EOL);
}
printf('<b>%s</b>: %s<br /><hr>', $city, $to);
printf('%s<br />%s', $sub, $msg);
$options = array(
'from' => 'aaa@qq.com',
'to' => $to,
'smtp_host' => 'smtp.126.com', //SMTP服务器
'smtp_port' => '25', //SMTP服务器端口
'smtp_username' => 'aaa@qq.com', //邮箱帐号
'smtp_password' => 'password', //邮箱密码
'subject' => $sub,
'content' => $msg,
'content_type' => 'TEXT',
'charset' => 'utf8',
'tls' => false
);
$mail->setOpt($options);
$ret = $mail->send();
//发送失败时输出错误码和错误信息
if ($ret === false)
var_dump($mail->errno(), $mail->errmsg());
else
echo $sub . '发送完毕!' . '<br />';
echo '<hr><hr>';
}
mysql_close($conn);
}
}
?>
这个地方需要做一点小的改动,就是把你自己的邮箱信息写上去。建议专门申请一个邮箱用来发送天气信息。下面说一下改哪里。
在func.php文件中,找到以下几行,根据注释改成你自己的邮箱即可。
'smtp_host' => 'smtp.126.com', //SMTP服务器
'smtp_port' => '25', //SMTP服务器端口
'smtp_username' => 'aaa@qq.com', //邮箱帐号
'smtp_password' => 'password', //邮箱密码
再新建一个名为get_guest_info.php的文件,复制以下代码并保存。这个文件实现了通过IP确定地理位置的功能。
<?php
/* 作用取得客户端的ip、地理信息、浏览器http://blog.qita.in
* 使用方法如下
$gifo = new get_guest_info();
$addr = $gifo->Getaddress_1();
echo $addr['country'].'<br />'.$addr['local'];
echo toUTF8("<br/>浏览器类型:").$gifo->GetBrowser();
echo toUTF8("<br/>浏览器语言:").toUTF8($gifo->GetLang());
echo toUTF8("<br/>操作系统:").$gifo->GetOs();
*/
require_once('phpcharset.php'); //字符编码格式转换
class get_guest_info
{
////获得访客浏览器类型
function GetBrowser()
{
if (!empty($_SERVER['HTTP_USER_AGENT'])) {
$br = $_SERVER['HTTP_USER_AGENT'];
if (preg_match('/MSIE/i', $br)) {
$br = 'MSIE';
} elseif (preg_match('/Firefox/i', $br)) {
$br = 'Firefox';
} elseif (preg_match('/Chrome/i', $br)) {
$br = 'Chrome';
} elseif (preg_match('/Safari/i', $br)) {
$br = 'Safari';
} elseif (preg_match('/Opera/i', $br)) {
$br = 'Opera';
} else {
$br = 'Other';
}
return $br;
} else {
return "获取浏览器信息失败!";
}
}
////获得访客浏览器语言
function GetLang()
{
if (!empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
$lang = $_SERVER['HTTP_ACCEPT_LANGUAGE'];
$lang = substr($lang, 0, 5);
if (preg_match("/zh-cn/i", $lang)) {
$lang = "简体中文";
} elseif (preg_match("/zh/i", $lang)) {
$lang = "繁体中文";
} else {
$lang = "English";
}
return $lang;
} else {
return "获取浏览器语言失败!";
}
}
////获取访客操作系统
function GetOs()
{
if (!empty($_SERVER['HTTP_USER_AGENT'])) {
$OS = $_SERVER['HTTP_USER_AGENT'];
if (preg_match('/win/i', $OS)) {
$OS = 'Windows';
} elseif (preg_match('/mac/i', $OS)) {
$OS = 'MAC';
} elseif (preg_match('/linux/i', $OS)) {
$OS = 'Linux';
} elseif (preg_match('/unix/i', $OS)) {
$OS = 'Unix';
} elseif (preg_match('/bsd/i', $OS)) {
$OS = 'BSD';
} else {
$OS = 'Other';
}
return $OS;
} else {
return "获取访客操作系统信息失败!";
}
}
////获得访客真实ip
function Getip()
{
if (!empty($_SERVER["HTTP_CLIENT_IP"])) {
$ip = $_SERVER["HTTP_CLIENT_IP"];
}
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { //获取代理ip
$ips = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
}
if ($ip) {
$ips = array_unshift($ips, $ip);
}
$count = count($ips);
for ($i = 0; $i < $count; $i++) {
if (!preg_match("/^(10|172\.16|192\.168)\./i", $ips[$i])) { //排除局域网ip
$ip = $ips[$i];
break;
}
}
$tip = empty($_SERVER['REMOTE_ADDR']) ? $ip : $_SERVER['REMOTE_ADDR'];
if ($tip == "127.0.0.1") { //获得本地真实IP
return $this->get_onlineip();
} else {
return $tip;
}
}
////获得本地真实IP
function get_onlineip()
{
$mip = file_get_contents("http://iframe.ip138.com/ic.asp");
if ($mip) {
preg_match("/\[.*\]/", $mip, $sip);
$p = array(
"/\[/",
"/\]/"
);
return preg_replace($p, "", $sip[0]);
} else {
return toUTF8("获取本地IP失败!");
}
}
////根据ip获得访客所在地地名:基于纯真数据库
function Getaddress_1($ip = '')
{
if (empty($ip)) {
$ip = $this->Getip();
}
require('qqwrt_parser.php');
$QQWry = new QQWry;
$ifErr = $QQWry->QQWry($ip);
$address = array();
$address['country'] = toUTF8($QQWry->Country);
$address['local'] = toUTF8($QQWry->Local);
return $address;
}
////根据ip获得访客所在地地名:从ip138获取
function Getaddress_2($ip = '')
{
//来自:XX省XX市 电信
if (empty($ip)) {
$ip = $this->Getip();
}
$get_url = sprintf('http://wap.ip138.com/ip_search.asp?ip=%s', $ip);
$mip = file_get_contents($get_url);
if ($mip) {
preg_match("/查询结果:(\S+)\s+(\S+)/", $mip, $sip);
$address = array();
$address['country'] = toUTF8($sip[1]);
$address['local'] = toUTF8($sip[2]);
return $address;
} else {
return toUTF8("获取本地IP失败!");
}
}
}
?>
再新建一个phpcharset.php文件,复制以下代码并保存。这个文件实现了字符串编码方式的转换,我这里主要是把其他编码格式转换成UTF8,以免引起中文乱码。
<?php
function phpcharset($data, $to)
{
if (is_array($data)) {
foreach ($data as $key => $val) {
$data[$key] = phpcharset($val, $to);
}
} else {
$encode_array = array(
'ASCII',
'UTF-8',
'GBK',
'GB2312',
'BIG5'
);
$encoded = mb_detect_encoding($data, $encode_array);
$to = strtoupper($to);
if ($encoded != $to) {
$data = mb_convert_encoding($data, $to, $encoded);
}
}
return $data;
}
function toUTF8($data)
{
return phpcharset($data, 'UTF-8');
}
function toGBK($data)
{
return phpcharset($data, 'GBK');
}
function toASCII($data)
{
return phpcharset($data, 'ASCII');
}
function toGB2312($data)
{
return phpcharset($data, 'GB2312');
}
function toBIG5($data)
{
return phpcharset($data, 'BIG5');
}
?>
然后继续新建一个php文件,名称为validation.php,用来实现对邮箱、城市名称等的校验,保证只有输入合法的邮箱地址和正确的城市名称才能订阅天气。代码如下。
<?php
function validateCity($city)
{
//if it's NOT valid
if (strlen($city) < 1)
return false;
//if it's valid
else
return true;
}
function validateEmail($email)
{
return preg_match("/^[a-zA-Z0-9]+[a-zA-Z0-9_.-]+[a-zA-Z0-9_-]aaa@qq.com[a-zA-Z0-9]+\.[a-zA-Z0-9]+(\.[a-zA-Z0-9]+)*$/", $email);
}
function isCityFound($city)
{
if (($_POST['city'] <> '北京') && (get_city_code($_POST['city']) == '101010100'))
return false;
else
return true;
}
?>
还需要再新建一个名为db-config.php文件,保存MySQL数据库的信息。代码很简单,如下所示:
<?php
/** The name of the database for SAE */
define('DB_NAME', SAE_MYSQL_DB);
/** MySQL database username */
define('DB_USER', SAE_MYSQL_USER);
/** MySQL database password */
define('DB_PASSWORD', SAE_MYSQL_PASS);
/** MySQL Master hostname */
define('DB_HOST_M', SAE_MYSQL_HOST_M . ':' . SAE_MYSQL_PORT);
/** MySQL Slaver hostname */
define('DB_HOST_S', SAE_MYSQL_HOST_S . ':' . SAE_MYSQL_PORT);
?>
最后还有一个php文件,名字叫做result.php。这个页面是提交订阅信息后的结果页面,根据你输入的信息,显示订阅成功,或者在订阅失败时给出提示。代码如下
<?php
require_once('func.php');
require_once('validation.php');
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title><?php echo '知天气 - ' . $title; ?></title>
</head>
<body>
<?php
$post_city = trim($_POST['city']);
$post_mail = trim($_POST['email']);
if (isset($_POST['sub']) && (!validateCity($post_city) || !validateEmail($_POST['email']) || !isCityFound($post_city))) {
echo '<h1>订阅失败</h1>';
echo '<div id="error">';
echo '<ul>';
if (!validateEmail($post_mail))
echo '<li><strong>邮箱错误:</strong>请输入您正确的邮箱地址!</li>';
if (!validateCity($post_city))
echo '<li><strong>城市错误:</strong>请输入您关注的城市名称!</li>';
elseif (!isCityFound($post_city))
echo '<li><strong>城市错误:</strong>未找到您要关注的城市,请重新输入。</li>';
echo '</ul>';
echo '</div>';
} elseif (isset($_POST['sub'])) {
add_user($post_mail, $post_city);
echo '<h1>订阅成功</h1>';
echo '<div id="error" class="valid">';
echo '<ul>';
printf('<li>您已成功订阅<a href="index.php?c=%s">%s天气预报</a>,感谢您的关注~</li>', get_city_code($post_city), $post_city);
echo '</ul>';
echo '</div>';
}
?>
<a href="index.php">返回首页</a>
</body>
</html>
现在差定时发送天气预报的php页面。再新建一个php文件,命名为send_weather.php。访问这个页面就会给所有订阅的天气预报的用户发送天气信息,我们的目标是实现定时自动发送,所以这个页面平时不需要访问,为了以示区别,专门给它建立一个文件夹,名字叫做cron,然后把send_weather.php文件放进cron文件夹。send_weather.php的代码如下所示:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>发送天气短信</title>
</head>
<body>
<?php
require_once('../func.php');
send_weather();
?>
</body>
</html>
为了实现定时发送天气预报,还需要加入定时信息。新建一个config.yaml文件,这个文件就是SAE应用的配置文件,这个文件要放在项目根目录下,也就是和index.php放在一起。然后打开config.yaml文件,把以下内容复制进去并保存。注意name和version那里填写你自己的SAE应用ID(也就是二级域名)和相应的版本号。这里边包含两条定时信息,分别是早上8点15和晚上18点15各发一次天气信息,应用路径其实都是send_weather.php,但是SAE的多个cron的url不能完全相同,如果多个cron中使用了相同的url,后面的cron会覆盖前面的cron。所以18点15那一条定时信息的URL路径中添加无用的参数"?cron=1"以避免覆盖。
name: tianqi123 version: 1 cron: - description: 每天早上8点15发送天气预报 url: cron/send_weather.php schedule: every day of month 08:15 - description: 每天晚上6点15发送天气预报 url: cron/send_weather.php?cron=1 schedule: every day of month 18:15
好了,到现在为止,所有的代码工作都完成了,那就上传到服务器吧。不过上传之前还是再确认一下有没有多或者少文件,以及文件路径是否正确。对比一下我的tianqi123文件夹结构,看看你的项目是这样的吗?
确认无误后就可以上传代码了,这一步还要使用SVN。
第四步:上传代码
在tianqi123这个文件夹下的空白处点南鼠标右键,选择TortoiseSVN——>Add,打开Add对话框。
在Add对话框中,确认所有的文件夹和文件都已经被选中,然后点击OK。
稍等片刻,当出现以下窗口时,增加文件就完成了。
点击OK关掉这个对话框,然后可以发现刚才选中的文件夹和文件的图标上都有一个加号,而tianqi123这个文件夹图标上多了一个红色的感叹号。然后在tianqi123文件夹上点右键并选择SVN Commit,进行代码提交。
点击SVN Commit之后会打开下边的对话框,确定所有代码都已经选择上,并且在Message框中写上本次代码提交的原因。注意Message一栏不能为空,不然无法提交代码。
单击“OK”开始同步,如果是第一次使用会弹出Authentication窗口进行身份验证,
- username:注册SAE时填写的 安全邮箱(并非微博帐号)
- password:注册SAE时填写的 安全密码(并非微博密码)
另外,如果您不希望每次使用都进行身份验证,可以勾选Save authentication复选框。
输入正确的帐号密码之后点击OK,就开始上传代码了。等到出现Complete At revision: 1(这个数字是Checkout时看到的那个数字加1)时,代码就上传成功了。是不是有点迫不及待想看看咱们的成果了呢?别急,还有最后一步。
第五步:初始化MySQL
因为我们用到了MySQL,而SAE应用默认情况下是没有启用MySQL服务的,所以我们还需要对MySQL进行初始化并进行简单的设置。
登录进去自己的SAE帐号,然后进入“我的应用”,在我创建的应用中,点击我们之前创建的那个应用,我这里就是“我的天气预报”。
然后就进入了“我的天气预报”的应用信息页面。点击左侧的服务管理中的MySQL,打开MySQL服务管理。
然后点击“点此初始化MySQL”按钮。然后会弹出安全认证对话框,输入安全密码(非微博密码)后点击安全验证按钮。
等待片刻,弹出初始化成功对话框时,说明MySQL已经初始化完成了。
关掉对话框,回到MySQL服务管理页面。然后单击“管理MySQL”按钮,打开PHPMyAdmin页面。
在这个页面中我们可以看到,在这个应用的数据库中还没有表,所以我们需要新建一个数据表了。直接用SQL代码进行操作吧,点击上图椭圆框中的SQL按钮,然后输入以下SQL代码,并点击执行,数据表就创建成功了。
SQL代码如下:
create table `subscriber`(
`ID` int NOT NULL AUTO_INCREMENT ,
`Mail` varchar(40) NOT NULL ,
`CityName` varchar(16) NOT NULL ,
`CityCode` varchar(9) NOT NULL ,
PRIMARY KEY (`ID`)
)
到此为止,所有的工作都已经完成了。打开浏览器,输入应用地址,我的应用地址就是http://tianqi123.sinaapp.com,终于看到成果了!!
结束语:
本文基本上是手把手地教大家创建了一个SAE天气应用。这个天气应用很简单,但是却可以给你的手机订阅一个免费的天气预报短信。当然,或许大家的手机上已经有天气预报的软件了,觉得这个天气短信有点多余了,其实不然,至少这个天气短信不需要任何流量。而且,也并不是所有人都在使用智能手机,你可以给你的父母、亲朋好友,给那些不会使用智能手机的人送上一份免费的天气预报。
本人也是PHP初学者,对HTML、CSS也是一知半解,所以本文只讨论了PHP的实现,并未涉及CSS的设计。因此,完成后的应用主页稍显简陋,大家将就看吧。
如果你看了本文,觉得自己动手新建一个SAE应用比较麻烦的话,可以访问我的“知天气”应用,同样也可以免费订阅天气哦~
知天气网址:http://zhitianqi.sinaapp.com/
【END】
本人由三思之旅原创,转载请注明出处!