最近开始学习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 ('test@test.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' => 'think3t@126.com', 'to' => $to, 'smtp_host' => 'smtp.126.com', //SMTP服务器 'smtp_port' => '25', //SMTP服务器端口 'smtp_username' => 'yourname@126.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' => 'yourname@126.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_-]+@[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`) )
相关推荐
手把手教你学DSP:基于TMS320F28335 手把手教你学DSP:基于TMS320F28335 手把手教你学DSP:基于TMS320F28335 手把手教你学DSP:基于TMS320F28335 手把手教你学DSP:基于TMS320F28335 手把手教你学DSP:基于TMS320F...
《手把手教你学DSP2812》是一本专为初学者设计的 DSP(Digital Signal Processor)学习指南,主要围绕TI公司的TMS320F2812 DSP芯片进行讲解。这本书以其全面且易懂的特性,为读者提供了一个深入理解数字信号处理及其...
【标题】"手把手教你学DSPPDF"是一份针对数字信号处理(DSP)初学者的教程性PDF文档,旨在引领读者逐步掌握这一领域的基础知识。该文档可能包含了从理论概念到实际应用的全面讲解,适合那些希望踏入数字信号处理世界...
手把手教你写天气预报,这个程序虽小,但是基本的东西都是具有的。另外,此文档由于做得倡促,在博客随便粘过来的。没有好好排版,如果看得不爽请到博客里看原文。
《手把手教你学DSP—基于TMS320F28335的应用开发及实战配套程序》这个压缩包文件,主要围绕着数字信号处理器(DSP)的应用开发展开,特别是针对Texas Instruments(TI)的TMS320F28335型号。TMS320F28335是一款高...
手把手教你学28335PDF文档,看了这个确实和2812有了对比
《手把手教你学51单片机》是一本专为初学者设计的嵌入式开发入门教程,旨在帮助读者从零开始掌握51单片机的基础知识和应用技能。51单片机是嵌入式系统中最基础且广泛应用的一类微控制器,广泛应用于智能家居、工业...
手把手教你学DSP28335高清pdf文件,北京航空航天大学出版社
手把手教你学DSP28335,PDF格式,有助于随时随地可以学习知识。
《手把手教你学51单片机C语言版》是一本专为初学者设计的教程,旨在帮助读者从零开始掌握51系列单片机的编程与应用。这本书由权威的电子技术教育平台www.kingst.org提供,是学习单片机C语言编程的宝贵资源。下面将...
《手把手教你学DSP—基于TMS320F28335的应用开发及实战》是一本深入浅出的教程,主要针对Texas Instruments(TI)的TMS320F28335数字信号处理器(DSP)进行讲解。这门课程涵盖的内容丰富,从基础到实践,为读者提供...
根据给出的文件信息,《手把手教你学dsp2812》是顾卫刚所著的一本关于DSP2812的教材书籍。DSP2812指的是德州仪器(Texas Instruments,简称TI)的TMS320F2812数字信号处理器。TMS320F2812是一款32位的高性能数字信号...
手把手教你学dsp F2812 顾伟刚
【标题】"手把手教你打造apk安装器"的教程涵盖了创建和使用自定义APK安装程序的核心技术。在Android平台上,APK是应用程序的二进制格式,通常通过Google Play或其他应用商店进行分发。然而,有时候我们可能需要创建...
《手把手教你构建自己的Linux系统》以如何使用源代码搭建一套Linux系统这一独特的角度介绍Linux系统的构成,主要内容包括走进GNU/Linux、LFS,Linux系统定制原理,制作GNU/Linux系统的准备工作,本地定制GNU/Linux...
《手把手教你构建自己的Linux系统》以如何使用源代码搭建一套Linux系统这一独特的角度介绍Linux系统的构成,主要内容包括走进GNU/Linux、LFS,Linux系统定制原理,制作GNU/Linux系统的准备工作,本地定制GNU/Linux...
《手把手教你构建自己的Linux系统》以如何使用源代码搭建一套Linux系统这一独特的角度介绍Linux系统的构成,主要内容包括走进GNU/Linux、LFS,Linux系统定制原理,制作GNU/Linux系统的准备工作,本地定制GNU/Linux...
“手把手教你DSP配套资料”这一压缩包很可能是包含了一系列关于DSP的学习材料,可能包括教程文档、示例代码、实验指导等。通过这些资料,你可以深入理解DSP的基本原理、算法和应用,逐步掌握实际操作技能,为你的...
教程名称:手把手教你整理自己的SQL Server日志课程目录:【】MSSQL数据库日志满的快速解决办法【】SQL2008删除过期备份【】sqlserver数据库事务日志备份与恢复原理【】SQL_server日志清除法【】利用日志传送实现高...
在《手把手教你学51单片机》中,宋雪松先生会讲解C语言的基本语法、变量类型、运算符、流程控制语句以及函数等概念,并结合51单片机的特性,教授如何编写能在单片机上运行的C程序。 接下来,我们将深入到单片机的...