Witam, próbuje nauczyć się działania AJAX, w tym celu pracuję z książką 'AJAX i PHP.
Tworzenie interaktywnych aplikacji internetowych'. Mój problem polega na fakcie, iż skrypt
z tej książki(ściągniety bezpośrednio z serwera wydawnictwa) dotyczący czatu AJAX, po
wrzuceniu na serwer nie działa. Co ciekawe w każdej przeglądarce wyświetla inny bład. Jako
początkującemu niesamowicie cięzko mi znaleźć przyczyny błedu. Jedynymi zmianami, które
poczyniłem to wstawienie poprawnych danych bazy mysql
config.php
<?php
// definiuje dane połączenia z bazą danych
define('DB_HOST', localhost
'); define('DB_USER', 'user');
define('DB_PASSWORD', 'test');
define('DB_DATABASE', 'database');
?>
error_handler.php
<?php
// ustawia metodę obsługi błędu użytkownika na error_handler
// funkcja obsługująca błędy
function error_handler($errNo, $errStr, $errFile, $errLine)
{
// czyści wygenerowane wcześniej dane wyjściowe
// komunikat o błędzie danych wyjściowych
$error_message = 'ERRNO: ' . $errNo . chr(10) .
'TEKST: ' . $errStr . chr(10) .
'LOKALIZACJA: ' . $errFile .
', linia ' . $errLine;
// zapobiega wykonywaniu innych skryptyów PHP
}
?>
chat.php
<?php
// odwołanie do pliku z klasą Chat
require_once("chat.class.php");
// jakie operacja maja być wykonane
$mode = $_POST['mode'];
// domyślnie ustawia ostatnie id na 0
$id = 0;
// tworzy nową instancję klasy Chat
$chat = new Chat();
// jeśli ma być wywołana metoda SendAndRetrieve
if($mode == 'SendAndRetrieveNew')
{
// pobiera parametry wysłanej wiadomości z aplikacji
$name = $_POST['name'];
$message = $_POST['message'];
$color = $_POST['color'];
$id = $_POST['id'];
// sprawdza, czy podane wartości są poprawne
if ($name != '' && $message != '' && $color != '')
{
// wysyła wiadomość do bazy danych
$chat->postMessage($name, $message, $color);
}
}
// jeżeli ma być wywołana metoda DeleteAndRetrieve
elseif($mode == 'DeleteAndRetrieveNew')
{
// usuwa istniejące wiadomości
$chat->deleteMessages();
}
// jeżeli ma być wywołana metoda Retrieve
elseif($mode == 'RetrieveNew')
{
// poniera identyfikator ostatniej wiadomości pobranej przez klienta
$id = $_POST['id'];
}
// czyści dane wyjściowe
// nagłówki są wysyłane aby zapobiec zapisywaniu starych danych przez przeglądarki
header('Expires: Mon, 26 Jul 1997 05:00:00 GMT'); header('Last-Modified: ' . gmdate('D, d M Y H:i:s') . 'GMT'); header('Cache-Control: no-cache, must-revalidate'); header('Content-Type: text/xml, charset=UTF-8'); // pobiera nową wiadomośc z serwera
echo $chat->retrieveNewMessages($id); ?>
chat.class.php
<?php
// uruchamia plik konfiguracyjny
require_once('config.php');
// uruchamia obsługę błędów
require_once('error_handler.php');
// klasa zawierająca funkcjonalności strony serwera
class Chat
{
// obsługuje bazę danych
private $mMysqli;
// konstruktor otwiera połączenie z bazą danych
function __construct()
{
// łączy się z bazą
$this->mMysqli = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_DATABASE);
}
// destruktor zamyka połączenie z bazą
public function __destruct()
{
$this->mMysqli->close();
}
// kasuje zawartość tabeli zawierającej wiadomości
public function deleteMessages()
{
// tworzy zapytanie SQL, które dodaje nową wiadomość do serwera
$query = 'TRUNCATE TABLE chat';
// wykonuje zapytanie SQL
$result = $this->mMysqli->query($query);
}
/*
Metoda postMessages dodaje nową wiadomość do bazy
- $name odpowiada nazwie użytkownika wysłanej wiadomości
- $messsage to wysłana wiadomość
- $color zawiera parametry koloru wybranego przez użytkownika
*/
public function postMessage($name, $message, $color)
{
// usuwa znaki specjalne przez dodaniem wiadomości do bazy
$name = $this->mMysqli->real_escape_string($name);
$message = $this->mMysqli->real_escape_string($message);
$color = $this->mMysqli->real_escape_string($color);
// tworzy zapytanie SQL, które dodaje nową wiadomość do serwera
$query = 'INSERT INTO chat(posted_on, user_name, message, color) ' .
'VALUES (NOW(), "' . $name . '" , "' . $message . '","' . $color . '")';
// wykonuje zapytanie SQL
$result = $this->mMysqli->query($query);
}
/*
Metoda retrieveMessages pobiera wiadomości, które zostały wysłane na serwer
- parametr $id jest wysyłany przez klienta i odpowiada identyfikatorowi ostatniej
wiadomości pobranej przez niego.
Wiadomości o późniejszych id będą pobrane z serwera i wysłane klientowi w formacie
XML
*/
public function retrieveNewMessages($id=0)
{
// usuwa znaki specjalne przez dodaniem wiadomości do bazy
$id = $this->mMysqli->real_escape_string($id);
// tworzy zapytanie SQL, które pobiera wiadomość do serwera
if($id>0)
{
// pobiera wiadomości świeższe niż te o danym $id
$query = 'SELECT chat_id, user_name, message, color, ' .
'DATE_FORMAT(posted_on, "%Y-%m-%d %H:%i:%s") ' . 'AS posted_on ' .
'FROM chat WHERE chat_id > ' . $id . ' ORDER BY chat_id ASC';
}
else
{
// przy pierwszym uruchomieniu wyświetla ostatnich 50 wiadomości z serwera
$query =
'SELECT chat_id, user_name, message, color, posted_on FROM ' .
'(SELECT chat_id, user_name, message, color, ' .
'DATE_FORMAT(posted_on, "%Y-%m-%d %H:%i:%s") AS posted_on ' . 'FROM chat ' .
'ORDER BY chat_id DESC ' . 'LIMIT 50) AS Last50 ' . 'ORDER BY chat_id ASC';
}
// wykonuje zapytanie
$result = $this->mMysqli->query($query);
// tworzy odpowiedź XML
$response = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>';
$response .= '<response>';
// wysyła czystą flagę
$response .= $this->isDatabaseCleared($id);
// sprawdza czy jest odpowiedź
if($result->num_rows)
{
// przegląda w pętli wszystkie przechwycone wiadomości, aby stworzyć wiadomość
wynikową
while ($row = $result->fetch_array(MYSQLI_ASSOC))
{
$id = $row['chat_id'];
$response .= '<id>' . $id . '</id>' .
'<color><![CDATA[' . $color . ']]></color>' .
'<time>' . $time . '</time>' .
'<name><![CDATA[' . $userName . ']]></name>' .
'<message><![CDATA[' . $message . ']]></message>';
}
// zamyka połączenie z bazą, jak szybko jest to możliwe
$result->close();
}
// kończy odpowiedź XML i wysyła ją
$response = $response . '</response>';
return $response;
}
/*
Metoda isDatabaseCleared sprawdza, czy baza została wyczyszczona od ostatniego wywołania
serwera
- parametr $id zawiera identyfikator ostatniej wiadomości pobranej rpzez klienta
*/
private function isDatabaseCleared($id)
{
if($id>0)
{
//sprawdzenie liczby wierszy o id mniejszym niż uzyskany od klienta mówi nam, czy
baza była ostatnio czyszczona
$check_clear = 'SELECT count(*) old FROM chat where chat_id<=' . $id;
$result = $this->mMysqli->query($check_clear);
$row = $result->fetch_array(MYSQLI_ASSOC);
// jeśli baza była czyszczona, tablica musi być przeładowana
if($row['old']==0)
return '<clear>true</clear>';
}
return '<clear>false</clear>';
}
}
?>
get_color.php
<?php
// nazwa pliku z obrazkiem
$imgfile='palette.png';
// otwiera plik z obrazkiem na stronie
$img=imagecreatefrompng($imgfile);
// pobiera współrzędne punktu klikniętego przez użytkownika
$offsetx=$_GET['offsetx'];
$offsety=$_GET['offsety'];
// pobiera kliknięty kolor
$rgb = ImageColorAt($img, $offsetx, $offsety);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
// zwraca kod koloru
?>
chat.css
body
{
font-family: Tahoma, Helvetica, sans-serif;
margin: 1px;
font-size: 12px;
text-align: left
}
#content
{
border: DarkGreen 1px solid;
margin-bottom: 10px
}
input
{
border: #999 1px solid;
font-size: 10px
}
#scroll
{
position: relative;
width: 340px;
height: 270px;
overflow: auto
}
.item
{
margin-bottom: 6px
}
#colorpicker
{
text-align:center
}
index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="pl" lang="pl"> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <link href="chat.css" rel="stylesheet" type="text/css" /> Twoja przeglądarka nie obsługuje JavaScript!!
<img src="palette.png" id="palette" alt="Color Palette" border="1" onclick="getColor(event);"/>
<input id="color" type="hidden" readonly="true" value="#000000" /> (tekst będzie wyglądać tak)
<input type="text" id="userName" maxlength="10" size="10" onblur="checkUsername();"/>
<input type="text" id="messageBox" maxlength="2000" size="50" onkeydown="handleKey(event)"/>
<input type="button" value="Wyślij" onclick="sendMessage();" /> <input type="button" value="Skasuj wszystko" onclick="deleteMessages();" />
chat.js part I
/* chatURL - URL do aktualizacji wiadomości */
var chatURL = "chat.php";
/* getColorURL - URL do pobrania wybranego koloru RGB */
var getColorURL = "get_color.php";
/* tworzy obiekty XMLHttpRequest, które zaktualizują wiadomości rozmowy i pobiorą wybrany kolor*/
var xmlHttpGetMessages = createXmlHttpRequestObject();
var xmlHttpGetColor = createXmlHttpRequestObject();
/* zmienna, która określa jak często łączyć się z serwerem*/
var updateInterval = 1000; // w milisekundach
// ustawione na true, wyświetla szczegółowy komunikat o błędach
var debugMode = true;
/* rozpoczyna zapisywanie wiadomości w pamięci podręcznej */
/* lastMessageID - tidentyfikator najświeższej wiadomości rozmowy */
var lastMessageID = -1;
/* mouseX, mouseY - współrzędne kursora myszy */
var mouseX,mouseY;
/* tworzy instancję obiektu XMLHttpRequest */
function createXmlHttpRequestObject()
{
//przechowa referencję do obiektu XMLHttpRequest
var xmlHttp;
// powinno zadziałać dla przeglądarek nowszych niż IE6
try
{
// próbuje utworzyć obiekt XMLHttpRequest
xmlHttp = new XMLHttpRequest();
}
catch(e)
{
// zakładając że przeglądarką jest IE6 lub starsza
var XmlHttpVersions
= new Array("MSXML2.XMLHTTP.6.0", "MSXML2.XMLHTTP.5.0",
"MSXML2.XMLHTTP.4.0",
"MSXML2.XMLHTTP.3.0",
"MSXML2.XMLHTTP",
"Microsoft.XMLHTTP");
// sprawdza każdy prog id, aż któryś zadziała
for (var i=0; i<XmlHttpVersions.length && !xmlHttp; i++)
{
try
{
// próbuje utworzyć obiekt XMLHttpRequest
xmlHttp = new ActiveXObject(XmlHttpVersions[i]);
}
catch (e) {}
}
}
// zwraca utworzony obiekt lub wyświetla wiadomość o błędzie
if (!xmlHttp)
alert("Błąd podczas tworzenia obiektu XMLHttpRequest.");
else
return xmlHttp;
}
/* ta funkcja rozpoczyna rozmowę; jest wykonywana w chwili załadowania strony */
function init()
{
// pobiera odwołanie do okna tekstowego, w którym użytkownik wpisuje nową wiadomość
var oMessageBox = document.getElementById("messageBox");
// zapobiega uruchomieniu funkcji autouzupełniania
oMessageBox.setAttribute("autocomplete", "off");
// odwołanie do tekstu próbnego
var oSampleText = document.getElementById("sampleText");
// ustawia kolor domyślny na czarny
oSampleText.style.color = "black";
// zapewnia nadanie użytkownikowi nazwy (np. generowanej automatycznie)
checkUsername();
// rozpoczyna aktualizację nowego okna
requestNewMessages();
}
// funkcja, która zapewnia, że użytkownik dostanie nazwę, choćby generowaną automatycznie
function checkUsername()
{
// zapewnia nadanie użytkownikowi nazwy (np. generowanej automatycznie)
var oUser=document.getElementById("userName");
if(oUser.value == "")
oUser
.value
= "Gość" + Math
.floor(Math
.random
() * 1000
);}
/* funkcja wywołana po wciśnięciu przycisku "Wyślij"*/
function sendMessage()
{
// zachowuje wiadomość w zmiennych lokalnych i czyści okienko tekstowe
var oCurrentMessage = document.getElementById("messageBox");
var currentUser = document.getElementById("userName").value;
var currentColor = document.getElementById("color").value;
// nie wysyła pustych wiadomości
if (trim(oCurrentMessage
.value
) != "" && trim(currentUser
) != "" && trim (currentColor
) != "") {
// jeśli musimy wysłać i pobrać wiadomość
params = "mode=SendAndRetrieveNew" +
"&id=" + encodeURIComponent(lastMessageID) +
"&color=" + encodeURIComponent(currentColor) +
"&name=" + encodeURIComponent(currentUser) +
"&message=" + encodeURIComponent(oCurrentMessage.value);
// dodaje wiadomość do kolejki
cache.push(params);
// czyści okno tekstowe
oCurrentMessage.value = "";
}
}
/* funkcja wywołana po wciśnięciu przycisku "Usuń wszystko" */
function deleteMessages()
{
// ustawia flagę, która określa, że wiadomości są usuwane
params = "mode=DeleteAndRetrieveNew";
// dodaje wiadomość do kolejki
cache.push(params);
}
/* wysyła asynchroniczne żądanie, aby pobrać nowe wiadomości, wysłać je lub usunąć*/
function requestNewMessages()
{
// pobiera nazwę użytkownika i kolor ze strony
var currentUser = document.getElementById("userName").value;
var currentColor = document.getElementById("color").value;
// kontynuuje jeśli xmlHttpGetMessages nie jest pusty
if(xmlHttpGetMessages)
{
try
{
// nie zaczyna nowej operacji na serwerze, jeśli jakaś jest wykonywana
if (xmlHttpGetMessages.readyState == 4 ||
xmlHttpGetMessages.readyState == 0)
{
// przechowa parametry potrzebne do wykonania żądania na serwerze
var params = "";
// jeśli w kolejce czekają wiadomości, to pobiera najstarszą
if (cache.length>0)
params = cache.shift();
// jeśli pamięć jest pusta, pobiera nową wiadomość
else
params = "mode=RetrieveNew" +
"&id=" +lastMessageID;
// wywołuje działania po stronie serwera
xmlHttpGetMessages.open("POST", chatURL, true);
xmlHttpGetMessages.setRequestHeader("Content-Type",
"application/x-www-form-urlencoded");
xmlHttpGetMessages.onreadystatechange = handleReceivingMessages;
xmlHttpGetMessages.send(params);
}
else
{
// sprawdza ponownie czy są nowe wiadomości
setTimeout("requestNewMessages();", updateInterval);
}
}
catch(e)
{
displayError(e.toString());
}
}
}
/* funkcja obsługująca odpowiedź HTTP podczas aktualizacji wiadomości*/
function handleReceivingMessages()
{
// kontynuuje jeśli proces jest zakończony
if (xmlHttpGetMessages.readyState == 4)
{
// kontynuuje, jeśli status HTTP ma wartość "OK"
if (xmlHttpGetMessages.status == 200)
{
try
{
// przetwarza odpowiedź serwera
readMessages();
}
catch(e)
{
// wyświetla wiadomość o błędzie
displayError(e.toString());
}
}
else
{
// wyświetla wiadomość o błędzie
displayError(xmlHttpGetMessages.statusText);
}
}
}
chat.js part II
/* funkcja obsługująca odpowiedź serwera podczas aktualizacji wiadomości*/
function readMessages()
{
// pobiera odpowiedź serwera
var response = xmlHttpGetMessages.responseText;
// błąd serwera?
if (response.indexOf("ERRNO") >= 0
|| response.indexOf("błąd:") >= 0
|| response.length == 0)
throw(response.length == 0 ? "Pusta odpowiedź serwera." : response);
// pobiera element dokumentu
response = xmlHttpGetMessages.responseXML.documentElement;
// pobiera flagę określającą czy okno rozmowy zostało wyczyszczone czy nie
clearChat =
response.getElementsByTagName("clear").item(0).firstChild.data;
// jeśli flaga ma wartość true, trzeba wyczyścić okno wiadomości
if(clearChat == "true")
{
// czyści okno wiadomości i zeruje id
document.getElementById("scroll").innerHTML = "";
lastMessageID = -1;
}
// pobiera tablice z odpowiedzi serwera
idArray = response.getElementsByTagName("id");
colorArray = response.getElementsByTagName("color");
nameArray = response.getElementsByTagName("name");
timeArray = response.getElementsByTagName("time");
messageArray = response.getElementsByTagName("message");
// dodaje nową wiadomość do okna rozmowy
displayMessages(idArray, colorArray, nameArray, timeArray, messageArray);
// przechowuje lokalnie ID ostatniej otrzymanej wiadomości
if(idArray.length>0)
lastMessageID = idArray.item(idArray.length - 1).firstChild.data;
// ponownie uruchamia sekwencję
setTimeout("requestNewMessages();", updateInterval);
}
/* funkcja dodająca nowe wiadomości do okna rozmowy */
function displayMessages(idArray, colorArray, nameArray, timeArray, messageArray)
{
// każdy przebieg pętli dodaje nową wiadomość
for(var i=0; i<idArray.length; i++)
{
// pobiera szczegóły wiadomości
var color = colorArray.item(i).firstChild.data.toString();
var time = timeArray
.item
(i
).firstChild
.data
.toString
(); var name = nameArray.item(i).firstChild.data.toString();
var message = messageArray.item(i).firstChild.data.toString();
// tworzy kod HTML, który wyświetli wiadomość
var htmlMessage = "";
htmlMessage += "<div class=\"item\" style=\"color:" + color + "\">";
htmlMessage
+= "[" + time + "] " + name
+ " powiedział: <br/>"; htmlMessage += message.toString();
htmlMessage += "</div>";
// wyświetla wiadomość
displayMessage (htmlMessage);
}
}
// wyświetla wiadomość
function displayMessage(message)
{
// pobiera obiekt scroll
var oScroll = document.getElementById("scroll");
// sprawdza, czy pasek jest przewinięty
var scrollDown = (oScroll.scrollHeight - oScroll.scrollTop <=
oScroll.offsetHeight );
// wyświetla wiadomość
oScroll.innerHTML += message;
// przewija na dół pasek przewijania
oScroll.scrollTop = scrollDown ? oScroll.scrollHeight : oScroll.scrollTop;
}
// funkcja wyświetlająca komunikat o błędzie
function displayError(message)
{
// wyświetla wiadomość o błędzie ze szczegółami technicznymi, jeśli debugMode ma ustawienie true
displayMessage("Błąd podczas dostępu do serwera! "+
(debugMode ? "<br/>" + message : ""));
}
/*obsługuje zdarzenie keydown aby określić, kiedy wciśnięto Enter*/
function handleKey(e)
{
// pobiera zdarzenie
e = (!e) ? window.event : e;
// pobiera kod wciśniętego znaku
code = (e.charCode) ? e.charCode : ((e.keyCode) ? e.keyCode :
((e.which) ? e.which : 0));
// obsługuje zdarzenie keydown
if (e.type == "keydown")
{
// jeśli został wciśnięty Enter (kod 13)
if(code == 13)
{
// wysyła bieżącą wiadomość
sendMessage();
}
}
}
/* usuwa spacje z początku i końca łańcucha*/
{
return s.replace(/(^\s+)|(\s+$)/g, "")
}
/* funkcja, która oblicza współrzędne kursora na stronie*/
function getMouseXY(e)
{
// specyficzne dla przeglądarki
if(window.ActiveXObject)
{
mouseX = window.event.x + document.body.scrollLeft;
mouseY = window.event.y + document.body.scrollTop;
}
else
{
mouseX = e.pageX;
mouseY = e.pageY;
}
}
/* wywołanie serwera do pobrania koloru RGB*/
function getColor(e)
{
getMouseXY(e);
// nic nie robi, jeśli obiekt XMLHttpRequest ma wartość null
if(xmlHttpGetColor)
{
// rozpoczyna ustalanie względnej pozycji myszy
var offsetX = mouseX;
var offsetY = mouseY;
// pobiera odwołania
var oPalette = document.getElementById("palette");
var oTd = document.getElementById("colorpicker");
// oblicza względną pozycję kursora w oknie
if(window.ActiveXObject)
{
offsetX = window.event.offsetX;
offsetY = window.event.offsetY;
}
else
{
offsetX -= oPalette.offsetLeft + oTd.offsetLeft;
offsetY -= oPalette.offsetTop + oTd.offsetTop;
}
// wywołuje serwer asynchronicznie, aby pobrać wybrany kolor
try
{
if (xmlHttpGetColor.readyState == 4 ||
xmlHttpGetColor.readyState == 0)
{
params = "?offsetx=" + offsetX + "&offsety=" + offsetY;
xmlHttpGetColor.open("GET", getColorURL+params, true);
xmlHttpGetColor.onreadystatechange = handleGettingColor;
xmlHttpGetColor.send(null);
}
}
catch(e)
{
// wyświetla komunikat o błędzie
displayError(xmlHttp.statusText);
}
}
}
/* funkcja obsługująca odpowiedź HTTP */
function handleGettingColor()
{
// jeśli proces zostanie zakończony, decyduje co zrobić ze zwróconymi danymi
if (xmlHttpGetColor.readyState == 4)
{
// tylko jeśli status HTTP jest "OK"
if (xmlHttpGetColor.status == 200)
{
try
{
//zmienia kolor
changeColor();
}
catch(e)
{
// wyświetla komunikat o błędzie
displayError(xmlHttpGetColor.statusText);
}
}
else
{
// wyświetla komunikat o błędzie
displayError(xmlHttpGetColor.statusText);
}
}
}
/* funkcja, która zmienia kolor wyświetlanej wiadomości*/
function changeColor()
{
response=xmlHttpGetColor.responseText;
// błąd serwera?
if (response.indexOf("ERRNO") >= 0 || response.indexOf("error:") >= 0
|| response.length == 0)
throw(response.length == 0 ? "Nie mogę zmienić koloru!" : response);
// zmienia kolor
var oColor = document.getElementById("color");
var oSampleText = document.getElementById("sampleText");
oColor.value = response;
oSampleText.style.color = response;
}