网站首页 > 网络编程教程 > Ajax教程 > ajax的server部分(php版)

ajax的server部分(php版)

  • 作者:互联网
  • 时间:2009-07-06 16:38:50

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; 分别触发自己的函数)



Server PHP Ajax


Default Words


divideby





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('MS***2.XMLHTTP.6.0',
                                    'MS***2.XMLHTTP.5.0',
                                    'MS***2.XMLHTTP.4.0',
                                    'MS***2.XMLHTTP.3.0',
                                    'MS***2.XMLHTTP',
                                    'Mi***soft.XMLHTTP');
    for (var i=0; i<Xm***tpVersions.length && !xmlHttp; i++)
    ...{
      try
 
      ...{
        // try to create XMLHttpRequest object
        xmlHttp = new ActiveXObject(XmlHttpVersions[i]);
      }
      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端的PH***hoXML.php文件发送异步请求
      xm***tp.open("GET", "PH***hoXML.php", true);
      xm***tp.onreadystatechange = handleRequestStateChange;
      xm***tp.send(null);
    }
    // display the error in case of failure
    catch (e)
    ...{
      alert("Can't connect to server: " + e.***tring());
    }
  }
}

///////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端的PH***MXML.php文件发送异步请求
      xm***tp.open("GET", "PH***MXML.php", true);
      xm***tp.onreadystatechange = handleRequestStateChange;
      xm***tp.send(null);
    }
    // display the error in case of failure
    catch (e)
    ...{
      alert("Can't connect to server: " + e.***tring());
    }
  }
}

// handles the response received from the server,Server端状态回调函数
function handleRequestStateChange()
...{

  if (xm***tp.readyState == 4)
  ...{
    // continue only if HTTP status is "OK"
    if (xm***tp.status == 200)
    ...{
      try
      ...{
          // read the message from the server
          var xmlResponse = xm***tp.responseXML;

            //捕获IE和Opera潜在的错误
            if(!xmlResponse||!xm***sponse.documentElement)
            ...{
                throw("Invalid XML structure:  "+xm***tp.responseText);
            }
            //捕获FireFox的潜在错误
            var rootNodeName=xm***sponse.documentElement.nodeName;
            if(rootNodeName=="parsererror")
            ...{
                throw("Invalid XML structure: "+xm***tp.responseText);
            }

            //获取Server端响应的XML响应并解析,到网页中显示
          // obtain the XML's document element
          xmlRoot = xm***sponse.documentElement
          // obtain arrays with book titles and ISBNs
          ci***rray=xmlRoot.getElementsByTagName("city");
          // generate HTML output
          var html = ""; 
          // iterate through the arrays and create an HTML structure
          for (var i=0; i<ci***rray.length; i++)
            html += ci***rray.item(i).f***tChild.data + "
";
          // obtain a reference to the

element on the page
          myDiv = do***ent.getElementById("show");
          // display the HTML output
          my***.innerHTML = "Server says:
" + html;
      }
      catch(e)
      ...{
        // display error message
        alert("Error reading the response: " + e.***tring());
      }
    }
    else
    ...{
      // display status message
      alert("There was a problem retrieving the data: " +
            xm***tp.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=do***ent.getElementById("firstNumber").value;
    var secondNumber=do***ent.getElementById("secondNumber").value;

    //设置为参数,对Server端的CS***ameter.php进行异步请求
   var param="firstNumber="+firstNumber+"&secondNumber="+secondNumber;

      // initiate reading a file from the server
      xm***tp.open("GET", "CS***ameter.php?"+param, true);
      xm***tp.onreadystatechange = handleRequestStateChangePara;
      xm***tp.send(null);
    }
    // display the error in case of failure
    catch (e)
    ...{
      alert("Can't connect to server: " + e.***tring());
    }
  }
}

//Server状态改变回调函数(Server端接受Client端传来的参数经过逻辑计算之后返回XML响应,Client端对XML进行解析,返回更新到页面中)
// handles the response received from the server
function handleRequestStateChangePara()
...{

  if (xm***tp.readyState == 4)
  ...{
    // continue only if HTTP status is "OK"
    if (xm***tp.status == 200)
    ...{
      try
      ...{
          // read the message from the server
          var xmlResponse = xm***tp.responseXML;
         
            //捕获IE和Opera潜在的错误
            if(!xmlResponse||!xm***sponse.documentElement)
            ...{
                throw("Invalid XML structure:  "+xm***tp.responseText);
            }
            //捕获FireFox的潜在错误
            var rootNodeName=xm***sponse.documentElement.nodeName;
            if(rootNodeName=="parsererror")
            ...{
                throw("Invalid XML structure: "+xm***tp.responseText);
            }

          // obtain the XML's document element
          xmlRoot = xm***sponse.documentElement
           
          ci***rray=xmlRoot.getElementsByTagName("result");
          // generate HTML output
          var html = ""; 
          // iterate through the arrays and create an HTML structure
          for (var i=0; i<ci***rray.length; i++)
            html += ci***rray.item(i).f***tChild.data + "
";
          // obtain a reference to the

element on the page
          myDiv = do***ent.getElementById("result");
          // display the HTML output
          my***.innerHTML = "Server says:
" + html;
      }
      catch(e)
      ...{
        // display error message
        alert("Error reading the response: " + e.***tring());
      }
    }
    else
    ...{
      // display status message
      alert("There was a problem retrieving the data: " +
            xm***tp.statusText);
    }
  }
}

Server端的PHP脚本(负责接受Client端的异步请求做出响应,并以XML格式返回到Client端)
PH***hoXML.php(PHP生成XML响应的第一种方法,echo输出XML内容)
//server端的PHP生成XML文件的第一种方法,直接echo出XML
header('Content-Type: text/xml');
// generate XML header
echo '';

echo '';
$cityArray=array('Paris','London','NewYork','Beijing','Tokoy');
foreach ($cityArray as $city)
{
    echo ''.$city.'';
}
echo '
';

?>

PH***MXML.php(PHP生成XML响应的第二种方法,使用PHP的DOM API,输出XML格式的响应)
  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端,server端根据传递的参数,生成满足要求的XML响应;(实现了client端和server端的参数交互)
见示例:
与1中一样,参数传递的PHP端的脚本如下CS***ameter.php(接受Client端form异步请求的参数,进行逻辑处理,并生成XML响应发回Client端)//自定义Server端的错误处理函数
require_once('er***_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.downcodes.com/
c)可以编写自己的PHP错误异常处理函数(不一定要求display_errors设置为on),将错误以明显的方式显示出来,便于调试;
通常自己编写异常处理函数如下:
显示定义的Server端错误异常抛出函数er***_handler.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: '.$er***.chr(10).'TEXT: '.$er***r.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) ap***me.php ;   <接受client端请求>
b) ap***me.class.php ;   <将server端的逻辑、数据库操作、错误处理等封装成类,包含属性、方法、构造函数、析构函数>
c) co***g.php
d) er***_handler.php

一个server端引入设计模式的例子:(设计Server端PHP脚本的程序架构,增强扩展性和重用性)
一个很简单的Keywords Suggest程序:(包括in***.html, cs***tyle.css, js.js以及PHP代码ph***uggest.php, su***st.class.php, er***_handler.php, co***g.php 支持数据库)
in***.html(cs***tyle.css, js.js; 注意两个JS客户端事件触发onkeyup,onclick)
onkeyup在用户输入的时候实时异步地向Server端发送请求,Server给出响应;onclick在用户点击search的时候,向Server发送请求



Design Pattern PHP AJAX (keywords suggest DEMO)
cs***tyle.css"/>



   
   


        Welcome to Design Pattern PHP AJAX (keywords suggest DEMO)
       

       

       

       



            suggest keywords:
           

       

   



cs***tyle.css
body
{...}{
    font-family: Arial;
    font-size: small;
    background-color: #fff;
}
.title
{...}{
    font-size:x-large;
}
di***roject
{...}{
    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('MS***2.XMLHTTP.6.0',
                                    'MS***2.XMLHTTP.5.0',
                                    'MS***2.XMLHTTP.4.0',
                                    'MS***2.XMLHTTP.3.0',
                                    'MS***2.XMLHTTP',
                                    'Mi***soft.XMLHTTP');
    for (var i=0; i<Xm***tpVersions.length && !xmlHttp; i++)
    ...{
      try
 
      ...{
        // try to create XMLHttpRequest object
        xmlHttp = new ActiveXObject(XmlHttpVersions[i]);
      }
      catch (e) ...{}
    }
  }
  if (!xmlHttp)
    alert("Error creating the XMLHttpRequest object.");
  else
    return xmlHttp;
}

//向id为show的div显示server端响应的正确
function display(message)
...{
    showDIV=do***ent.getElementById("show");
    sh***IV.innerHTML=message;
}
//向id为show的div显示server端响应的错误信息
function displayError(errormessage)
...{
    //显示出错信息
    display("Error retrieving the new message!
"+errormessage);
}

///////////////////////////////////////////////////////////
//2. event-driven函数(keyup函数)
///////////////////////////////////////////////////////////
var keyupAddress="ph***uggest.php?action=keyup&keyword=";
function keyup()
...{
    if(xmlHttp)
    ...{
        //server不忙的时候发送异步请求
        if(xm***tp.readyState==0||xm***tp.readyState==4)
        ...{
            try
            ...{
                var keyword=do***ent.getElementById("keyword").value;
                //发出异步请求
                xm***tp.open("GET",keyupAddress+keyword,true);
                xm***tp.onreadystatechange=handlereadystatechange;
                xm***tp.send(null);
            }
            catch(e)
            ...{
                displayError(e.***tring);
            }           
        }
    }
}
///////////////////////////////////////////////////////////
//3. 回调函数,server端响应状态发生变化后激发该函数
///////////////////////////////////////////////////////////
function handlereadystatechange()
...{
    if(xm***tp.readyState==4)
    ...{
        if(xm***tp.status==200)
        ...{
            try
            ...{
                //获取server端响应
                var xmlResponse = xm***tp.responseXML;
                su***stArray=xmlResponse.getElementsByTagName("suggest");
                var showText="";
                for(var i=0;i<su***stArray.length;i++)
                ...{
                    var textNodes=suggestArray[i].getElementsByTagName("text");
                    var timesNodes=suggestArray[i].getElementsByTagName("times");
                    for(var j=0;j<te***odes.length;j++)
                    ...{
                        showText+=textNodes[j].childNodes[0].nodeValue+" ("+timesNodes[j].childNodes[0].nodeValue+")
";   
                    }
                }
                //显示响应到页面中
                display(showText);
            }
            catch(e)
            ...{
                displayError(e.***tring());
            }
        }
    }
}
///////////////////////////////////////////////////////////
//2. event-driven函数(search函数)
///////////////////////////////////////////////////////////
var searchAddress="ph***uggest.php?action=search&keyword=";
function search()
...{
    if(xmlHttp)
    ...{
        //server不忙的时候发送异步请求
        if(xm***tp.readyState==0||xm***tp.readyState==4)
        ...{
            try
            ...{
                var keyword=do***ent.getElementById("keyword").value;
                //发出异步请求
                xm***tp.open("GET",searchAddress+keyword,true);
                xm***tp.onreadystatechange=handlereadystatechange;
                xm***tp.send(null);
            }
            catch(e)
            ...{
                displayError(e.***tring);
            }           
        }
    }
}

最后注意:Server端PHP脚本的程序架构(su***st.php为Server端的主要处理函数,另外su***st.class.php,er***_handler.php,co***g.php等)
su***st.php(获取Client端的参数,并调用suggest类的两个方法,生成XML格式的响应发回到Client端)
require_once('su***st.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;
?>su***st.class.php
require_once('er***_handler.php');
require_once('co***g.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='';
        if($suggest_num==0)
        {
            //$strOUT=$strOUT.''.$keyword.'0';
        }
        else
        {
            $strOUT=$strOUT."";
            for($i=0;$i<$suggest_num;$i++)
            {
              $suggest_row = $suggest_result->fetch_row();
              $strOUT=$strOUT.''.$suggest_row[1].''.$suggest_row[2].'';
            }
           $strOUT=$strOUT.'
';            
        }
       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='';       
        //已经存在,增加次数
        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.''.$keyword.''.$times_now.'';
        }
        else
        {
        //不存在保存插入
            $insert_query='insert into keywords(keyword, times) values (''.$keyword.'',1)';
            $insert_result=$this->conn->query($insert_query);
            $strOUT=$strOUT.''.$keyword.'1';
        }
       return $strOUT;
    }
}
?>
最后两个函数,co***g.php保存应用程序配置信息(如 数据库配置信息)
define('DB_HOST', 'localhost');
define('DB_USER','phpajaxuser');
define('DB_PASSWORD','phpajaxuser');
define('DB_DATABASE','phpajax');
?>
er***_handler.php保存自定义异常处理
//设置用户自定义错误处理函数
set_error_handler('error_handler', E_ALL);

function error_handler($errNo,$errStr,$errFile,$errLine)
{
    if(ob_get_length()) ob_clean();

    $error_message='ERRNO: '.$er***.chr(10).'TEXT: '.$er***r.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;
或者CURLww***hp.net/curl