|
Server端的任务通常是根据Client的请求,进行逻辑操作,并将结果响应返回。这个响应通常为XML格式(因此server端需要使用PHP的DOM创建XML响应) 1.PHP使用DOM创建XML响应,供client端的JS解析然后在页面中显示;(因此需要熟练PHP的DOM API) 其实,PHP生成XML的方法有两种: 使用DOM API;(方法一) 另一种是直接将XML的内容echo出去即可;(方法二) 见示例: HTML页面(包含三个JS触发函数:onmouseover, onmouseout, onclick; 分别触发自己的函数) <!doctype html public "-//w3c//dtd html 4.0 tRANSITIONAL//en"> <html> <head> <title> Server PHP Ajax </title> <script type="text/javascript" src="js.js"></script> </head> <body> <span onmouseover="PHPechoXML()" onmouseout="PHPDOMXML()">Default Words</span> <div id="show"></div> divide<input type="text" id="firstNumber"/>by <input type="text" id="secondNumber"/> <input type="button" value="Send" onclick="CSparameter()"/> <div id="result"></div> </body> </html> JS页面(分别定义三个JS触发函数:PHPechoXML, PHPDOMXML, 以及CSparameter) 其中有XMLHttpRequest对象创建函数,以及各自的Server响应处理函数 ///////1. 创建XMLHttpRequest对象 var xmlHttp = createXmlHttpRequestObject(); function createXmlHttpRequestObject() ...{ var xmlHttp; try ...{ // try to create XMLHttpRequest object xmlHttp = new XMLHttpRequest(); } catch(e) ...{ // assume IE6 or older var XmlHttpVersions = new Array('MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'); for (var i=0; i<XmlHttpVersions.length && !xmlHttp; i++) ...{ try ...{ // try to create XMLHttpRequest object xmlHttp = new ActiveXObject(XmlHttpVersions); } catch (e) ...{} } } if (!xmlHttp) alert("Error creating the XMLHttpRequest object."); else return xmlHttp; }
///////2. JavaScript事件响应函数(onmouseover触发) // read a file from the server function PHPechoXML() ...{ // only continue if xmlHttp isn't void if (xmlHttp) ...{ // try to connect to the server try ...{ // initiate reading a file from the server //向Server端的PHPechoXML.php文件发送异步请求 xmlHttp.open("GET", "PHPechoXML.php", true); xmlHttp.onreadystatechange = handleRequestStateChange; xmlHttp.send(null); } // display the error in case of failure catch (e) ...{ alert("Can't connect to server: " + e.toString()); } } } ///////3. JavaScript事件响应函数(onmouseout触发) function PHPDOMXML() ...{ // only continue if xmlHttp isn't void if (xmlHttp) ...{ // try to connect to the server try ...{ // initiate reading a file from the server //向Server端的PHPDOMXML.php文件发送异步请求 xmlHttp.open("GET", "PHPDOMXML.php", true); xmlHttp.onreadystatechange = handleRequestStateChange; xmlHttp.send(null); } // display the error in case of failure catch (e) ...{ alert("Can't connect to server: " + e.toString()); } } } // handles the response received from the server,Server端状态回调函数 function handleRequestStateChange() ...{ if (xmlHttp.readyState == 4) ...{ // continue only if HTTP status is "OK" if (xmlHttp.status == 200) ...{ try ...{ // read the message from the server var xmlResponse = xmlHttp.responseXML; //捕获IE和Opera潜在的错误 if(!xmlResponse||!xmlResponse.documentElement) ...{ throw("Invalid XML structure: "+xmlHttp.responseText); } //捕获FireFox的潜在错误 var rootNodeName=xmlResponse.documentElement.nodeName; if(rootNodeName=="parsererror") ...{ throw("Invalid XML structure: "+xmlHttp.responseText); } //获取Server端响应的XML响应并解析,到网页中显示 // obtain the XML's document element xmlRoot = xmlResponse.documentElement; // obtain arrays with book titles and ISBNs cityArray=xmlRoot.getElementsByTagName("city"); // generate HTML output var html = ""; // iterate through the arrays and create an HTML structure for (var i=0; i<cityArray.length; i++) html += cityArray.item(i).firstChild.data + "<br/>"; // obtain a reference to the <div> element on the page myDiv = document.getElementById("show"); // display the HTML output myDiv.innerHTML = "Server says: <br />" + html; } catch(e) ...{ // display error message alert("Error reading the response: " + e.toString()); } } else ...{ // display status message alert("There was a problem retrieving the data: " + xmlHttp.statusText); } } } ///////4. JavaScript事件响应函数(onclick触发) function CSparameter() ...{ // only continue if xmlHttp isn't void if (xmlHttp) ...{ // try to connect to the server try ...{ //获取form中的值 var firstNumber=document.getElementById("firstNumber").value; var secondNumber=document.getElementById("secondNumber").value; //设置为参数,对Server端的CSparameter.php进行异步请求 var param="firstNumber="+firstNumber+"&secondNumber="+secondNumber; // initiate reading a file from the server xmlHttp.open("GET", "CSparameter.php?"+param, true); xmlHttp.onreadystatechange = handleRequestStateChangePara; xmlHttp.send(null); } // display the error in case of failure catch (e) ...{ alert("Can't connect to server: " + e.toString()); } } } //Server状态改变回调函数(Server端接受Client端传来的参数经过逻辑计算之后返回XML响应,Client端对XML进行解析,返回更新到页面中) // handles the response received from the server function handleRequestStateChangePara() ...{ if (xmlHttp.readyState == 4) ...{ // continue only if HTTP status is "OK" if (xmlHttp.status == 200) ...{ try ...{ // read the message from the server var xmlResponse = xmlHttp.responseXML; //捕获IE和Opera潜在的错误 if(!xmlResponse||!xmlResponse.documentElement) ...{ throw("Invalid XML structure: "+xmlHttp.responseText); } //捕获FireFox的潜在错误 var rootNodeName=xmlResponse.documentElement.nodeName; if(rootNodeName=="parsererror") ...{ throw("Invalid XML structure: "+xmlHttp.responseText); } // obtain the XML's document element xmlRoot = xmlResponse.documentElement; cityArray=xmlRoot.getElementsByTagName("result"); // generate HTML output var html = ""; // iterate through the arrays and create an HTML structure for (var i=0; i<cityArray.length; i++) html += cityArray.item(i).firstChild.data + "<br/>"; // obtain a reference to the <div> element on the page myDiv = document.getElementById("result"); // display the HTML output myDiv.innerHTML = "Server says: <br />" + html; } catch(e) ...{ // display error message alert("Error reading the response: " + e.toString()); } } else ...{ // display status message alert("There was a problem retrieving the data: " + xmlHttp.statusText); } } } Server端的PHP脚本(负责接受Client端的异步请求做出响应,并以XML格式返回到Client端) PHPechoXML.php(PHP生成XML响应的第一种方法,echo输出XML内容) <?php //server端的PHP生成XML文件的第一种方法,直接echo出XML header('Content-Type: text/xml'); // generate XML header echo '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'; echo '<cities>'; $cityArray=array('Paris','London','NewYork','Beijing','Tokoy'); foreach ($cityArray as $city) { echo '<city>'.$city.'</city>'; } echo '</cities>'; ?> PHPDOMXML.php(PHP生成XML响应的第二种方法,使用PHP的DOM API,输出XML格式的响应) <?php header('Content-Type: text/xml'); $cityArray=array('Shanghai','Beijing','Shanxi','Shandong'); //创建一个XML文档 $dom=new DOMDocument(); //最外层的Tag $citiesTag=$dom->createElement('cities'); $dom->appendChild($citiesTag); //里面的Tag可以通过循环产生 foreach ($cityArray as $city) { $cityTag=$dom->createElement('city'); $cityName=$dom->createTextNode($city); $cityTag->appendChild($cityName); $citiesTag->appendChild($cityTag); } //将XML结构保存为字符串并输出 $xmlString=$dom->saveXML(); echo $xmlString; ?> 2. client端的与Server端的参数传递: client端的网页中可以有form,这样可以将参数传递到server端<GET或POST方法,变量或XML>,server端根据传递的参数,生成满足要求的XML响应;(实现了client端和server端的参数交互) 见示例: 与1中一样,参数传递的PHP端的脚本如下CSparameter.php(接受Client端form异步请求的参数,进行逻辑处理,并生成XML响应发回Client端)<?php //自定义Server端的错误处理函数 require_once('error_handler.php'); header('Content-Type: text/xml'); //接受Client端异步请求的参数 $firstNumber=$_GET['firstNumber']; $secondNumber=$_GET['secondNumber']; //进行逻辑计算 $result=$firstNumber/$secondNumber; //生成XML格式的响应向Client端返回 $dom=new DOMDocument(); $resultsTag=$dom->createElement('results'); $dom->appendChild($resultsTag); $resultTag=$dom->createElement('result'); $resultText=$dom->createTextNode($result); $resultTag->appendChild($resultText); $resultsTag->appendChild($resultTag); $xmlString=$dom->saveXML(); echo $xmlString; ?> 3. PHP端的错误异常(这里说的错误或异常都是指逻辑错误)处理: a)PHP默认情况下,发生错误或异常的时候,不会将异常抛出(这是因为php.ini中display_errors的默认置为off,错误将被保存在Apache错误日志记录中),因此编写起来很难调试。<往往浏览器显示的错不太容易定位> b)但如果将display_errors设置为on后,错误将显示出来,但是不友好的出错信息. http://www.knowsky.com/ c)可以编写自己的PHP错误异常处理函数(不一定要求display_errors设置为on),将错误以明显的方式显示出来,便于调试; 通常自己编写异常处理函数如下: 显示定义的Server端错误异常抛出函数error_handler.php(PHP程序中可以方便地复用) <?php //set a user-defined error handler function用户自定义出错异常处理方法 set_error_handler('error_handler', E_ALL); function error_handler($errNo,$errStr,$errFile,$errLine) { //如果输出缓存非空,将其置空 if(ob_get_length()) ob_clean(); //定义自定义输出 $error_message='ERRNO: '.$errNo.chr(10).'TEXT: '.$errStr.chr(10).'LOCATION: '.$errFile.', Line'.$errLine; echo $error_message; exit; } ?> 4.server端存取数据库<使用MySQL存取数据,从而实现真正的动态> 这个已经很经典了,可以使用MySQL或MSSQL、Oracle等 a)打开数据库;b)SQL语句Query c)关闭数据库 5.server端PHP程序封装和体系结构(server端php程序引入设计模式) a) appname.php <接受client端请求> b) appname.class.php <将server端的逻辑、数据库操作、错误处理等封装成类,包含属性、方法、构造函数、析构函数> c) config.php d) error_handler.php 一个server端引入设计模式的例子:(设计Server端PHP脚本的程序架构,增强扩展性和重用性) 一个很简单的Keywords Suggest程序:(包括index.html, css/style.css, js.js以及PHP代码php/suggest.php, suggest.class.php, error_handler.php, config.php 支持数据库) index.html(css/style.css, js.js; 注意两个JS客户端事件触发onkeyup,onclick) onkeyup在用户输入的时候实时异步地向Server端发送请求,Server给出响应;onclick在用户点击search的时候,向Server发送请求 <!doctype html public "-//w3c//dtd html 4.0 tRANSITIONAL//en"> <html> <head> <title> Design Pattern PHP AJAX (keywords suggest DEMO) </title> <link type="text/css" rel="stylesheet" href="css/style.css"/> <script type="text/javascript" src="js.js"></script> </head> <body> <noscript> <strong>This example requires a JavaScript-enabled browser!</strong> </noscript> <div class="project"> <span class="title">Welcome to Design Pattern PHP AJAX (keywords suggest DEMO) </span> <br /> <br /> <div class="news"> <br /><input type="text" id="keyword" onkeyup="keyup()" /><input type="button" id="search" onclick="search()" value="search"><br /><br /> suggest keywords: <div id="show"></div> </div> </div> </body> </html> css/style.css body {...}{ font-family: Arial; font-size: small; background-color: #fff; } .title {...}{ font-size:x-large; } div.project {...}{ background-color: #99ccff; padding:5px; border:#000099 1px solid; } div.news {...}{ background-color:#fffbb8; padding:2px; border: 1px dashed; } #show {...}{ color: #008000; font-style: italic; }js.js(JS中定义响应函数以及Client处理Server响应的回调函数) /////////////////////////////////////////////////////////// //1.创建XMLHttpRequest对象 /////////////////////////////////////////////////////////// var xmlHttp = createXmlHttpRequestObject(); function createXmlHttpRequestObject() ...{ var xmlHttp; try ...{ // try to create XMLHttpRequest object xmlHttp = new XMLHttpRequest(); } catch(e) ...{ // assume IE6 or older var XmlHttpVersions = new Array('MSXML2.XMLHTTP.6.0', 'MSXML2.XMLHTTP.5.0', 'MSXML2.XMLHTTP.4.0', 'MSXML2.XMLHTTP.3.0', 'MSXML2.XMLHTTP', 'Microsoft.XMLHTTP'); for (var i=0; i<XmlHttpVersions.length && !xmlHttp; i++) ...{ try ...{ // try to create XMLHttpRequest object xmlHttp = new ActiveXObject(XmlHttpVersions); } catch (e) ...{} } } if (!xmlHttp) alert("Error creating the XMLHttpRequest object."); else return xmlHttp; } //向id为show的div显示server端响应的正确 function display(message) ...{ showDIV=document.getElementById("show"); showDIV.innerHTML=message; } //向id为show的div显示server端响应的错误信息 function displayError(errormessage) ...{ //显示出错信息 display("Error retrieving the new message!<br/>"+errormessage); } /////////////////////////////////////////////////////////// //2. event-driven函数(keyup函数) /////////////////////////////////////////////////////////// var keyupAddress="php/suggest.php?action=keyup&keyword="; function keyup() ...{ if(xmlHttp) ...{ //server不忙的时候发送异步请求 if(xmlHttp.readyState==0||xmlHttp.readyState==4) ...{ try ...{ var keyword=document.getElementById("keyword").value; //发出异步请求 xmlHttp.open("GET",keyupAddress+keyword,true); xmlHttp.onreadystatechange=handlereadystatechange; xmlHttp.send(null); } catch(e) ...{ displayError(e.toString); } } } } /////////////////////////////////////////////////////////// //3. 回调函数,server端响应状态发生变化后激发该函数 /////////////////////////////////////////////////////////// function handlereadystatechange() ...{ if(xmlHttp.readyState==4) ...{ if(xmlHttp.status==200) ...{ try ...{ //获取server端响应 var xmlResponse = xmlHttp.responseXML; suggestArray=xmlResponse.getElementsByTagName("suggest"); var showText=""; for(var i=0;i<suggestArray.length;i++) ...{ var textNodes=suggestArray.getElementsByTagName("text"); var timesNodes=suggestArray.getElementsByTagName("times"); for(var j=0;j<textNodes.length;j++) ...{ showText+=textNodes[j].childNodes[0].nodeValue+" ("+timesNodes[j].childNodes[0].nodeValue+") <br />"; } } //显示响应到页面中 display(showText); } catch(e) ...{ displayError(e.toString()); } } } } /////////////////////////////////////////////////////////// //2. event-driven函数(search函数) /////////////////////////////////////////////////////////// var searchAddress="php/suggest.php?action=search&keyword="; function search() ...{ if(xmlHttp) ...{ //server不忙的时候发送异步请求 if(xmlHttp.readyState==0||xmlHttp.readyState==4) ...{ try ...{ var keyword=document.getElementById("keyword").value; //发出异步请求 xmlHttp.open("GET",searchAddress+keyword,true); xmlHttp.onreadystatechange=handlereadystatechange; xmlHttp.send(null); } catch(e) ...{ displayError(e.toString); } } } } 最后注意:Server端PHP脚本的程序架构(suggest.php为Server端的主要处理函数,另外suggest.class.php,error_handler.php,config.php等) suggest.php(获取Client端的参数,并调用suggest类的两个方法,生成XML格式的响应发回到Client端) <?php require_once('suggest.class.php'); header('Content-Type: text/xml'); //确定用户浏览器不会缓存结果 header('Expires: Wed, 23 Dec 1980 00:30:00 GMT'); header('Last-Modified: '.gmdate('D, d M Y H:i:s').' GMT' ); header('Cache-Control: no-cache, must-revalidate'); header('Pragma: no-cache'); $action=$_GET['action']; $keyword=$_GET['keyword']; $oSuggest=new suggest(); if($action=='keyup'&&$keyword!='') { $suggestXML=$oSuggest->getSuggests($keyword); } if($action=='search'&&$keyword!='') { $suggestXML=$oSuggest->submitKeyword($keyword); } echo $suggestXML; ?>suggest.class.php类 <?php require_once('error_handler.php'); require_once('config.php'); class suggest { //成员变量 private $conn; //构造函数, 数据库链接 function __construct() { $this->conn=new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_DATABASE); if (mysqli_connect_errno()) { printf("Connect failed: %s ", mysqli_connect_error()); exit(); } } //析构函数,断开数据库链接 function __destruct() { $this->conn->close(); } //getSuggests成员函数(该函数主要响应Client端action=keyup,即用户正在输入时候的异步请求) public function getSuggests($keyword) { //产生suggest(产生数据库中与所输入关键词前半部分相同的关键词) $suggest_query='select * from keywords where keyword like ''.$keyword.'%' order by times desc limit 5'; $suggest_result=$this->conn->query($suggest_query); $suggest_num=$suggest_result->num_rows; $strOUT='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'; if($suggest_num==0) { //$strOUT=$strOUT.'<suggests><suggest><text>'.$keyword.'</text><times>0</times></suggest></suggests>'; } else { $strOUT=$strOUT."<suggests>"; for($i=0;$i<$suggest_num;$i++) { $suggest_row = $suggest_result->fetch_row(); $strOUT=$strOUT.'<suggest><text>'.$suggest_row[1].'</text><times>'.$suggest_row[2].'</times></suggest>'; } $strOUT=$strOUT.'</suggests>'; } return $strOUT; } //submitKeyword成员函数(该函数主要响应Client端action=search,即用户点击search时候的异步请求) public function submitKeyword($keyword) { $select_query='select * from keywords where keyword=''.$keyword.'''; $select_result=$this->conn->query($select_query); $select_num=$select_result->num_rows; //遇到新的keywords添加到数据库中,遇到已有的keywords增加次数 $strOUT='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'; //已经存在,增加次数 if($select_num!=0) { $select_row = $select_result->fetch_row(); $times_now=$select_row[2]; $times_now=$times_now+1; $update_query='update keywords set times ='.$times_now.' where keyword=''.$keyword.'''; $update_result=$this->conn->query($update_query); $strOUT=$strOUT.'<suggests><suggest><text>'.$keyword.'</text><times>'.$times_now.'</times></suggest></suggests>'; } else { //不存在保存插入 $insert_query='insert into keywords(keyword, times) values (''.$keyword.'',1)'; $insert_result=$this->conn->query($insert_query); $strOUT=$strOUT.'<suggests><suggest><text>'.$keyword.'</text><times>1</times></suggest></suggests>'; } return $strOUT; } } ?> 最后两个函数,config.php保存应用程序配置信息(如 数据库配置信息) <?php define('DB_HOST', 'localhost'); define('DB_USER','phpajaxuser'); define('DB_PASSWORD','phpajaxuser'); define('DB_DATABASE','phpajax'); ?> error_handler.php保存自定义异常处理 <?php //设置用户自定义错误处理函数 set_error_handler('error_handler', E_ALL); function error_handler($errNo,$errStr,$errFile,$errLine) { if(ob_get_length()) ob_clean(); $error_message='ERRNO: '.$errNo.chr(10).'TEXT: '.$errStr.chr(10).'LOCATION: '.$errFile.' Line: '.$errLine; echo $error_message; exit; } ?>最后还需要sql语句向数据库中添加用于保存keywords的database CREATE TABLE `keywords` ( `id` int(10) unsigned NOT NULL auto_increment, `keyword` varchar(32) NOT NULL default '', `times` int(10) unsigned NOT NULL default '0', PRIMARY KEY (`id`) ) TYPE=MyISAM AUTO_INCREMENT=1 ; 6.关于PHP的小知识,以后研究: PHP从远程服务器读取数据的方法(有点儿类似Web Crawl): file_get_contents; 或者CURL<Client URL Library>www.php.net/curl
|
一共有 7 条评论