10. Servidores em PHP
Como os programas PHP podem ser executados por um servidor WEB, tal programa se torna um programa servidor capaz de atender a vários clientes. Do ponto de vista do cliente, chamar um serviço WEB equivale a solicitar o URL desse serviço. O cliente pode ser escrito em qualquer linguagem, inclusive em PHP. Nesse último caso, utilizam-se as funções de rede que acabamos de ver. Além disso, precisamos saber “conversar” com um serviço WEB, ou seja, compreender o protocolo http de comunicação entre um servidor web e seus clientes. Esse é o objetivo dos programas a seguir.
O cliente web descrito no parágrafo 9.2 nos permitiu descobrir uma parte do protocolo HTTP.

Em sua versão mais simples, as trocas entre cliente e servidor são as seguintes:
- o cliente abre uma conexão com a porta 80 do servidor web
- ele faz uma solicitação referente a um documento
- o servidor web envia o documento solicitado e encerra a conexão
- o cliente, por sua vez, encerra a conexão
O cliente pode ser de diversos tipos: um texto no formato HTML, uma imagem, um vídeo... Pode ser um documento existente (documento estático) ou um documento gerado dinamicamente por um script (documento dinâmico). Neste último caso, fala-se em programação web. O script de geração dinâmica de documentos pode ser escrito em diversas linguagens: PHP, Python, Perl, Java, Ruby, C#, VB.net, ...
Aqui, utilizamos PHP para gerar dinamicamente documentos de texto.
![]() |
- em [1], o cliente estabelece uma conexão com o servidor, solicita um script PHP e, opcionalmente, envia parâmetros para esse script
- No [2], o servidor web faz com que o script PHP seja executado pelo interpretador PHP. Esse script gera um documento que é enviado ao cliente [3]
- o servidor encerra a conexão. O cliente faz o mesmo.
O servidor web pode atender a vários clientes ao mesmo tempo. Com o pacote de software WampServer, o servidor web é um servidor Apache, um servidor de código aberto da Apache Foundation (http://www.apache.org/). Nas aplicações a seguir, o WampServer deve ser iniciado. Isso ativa três programas: o servidor web Apache, o SGBD MySQL e o interpretador PHP.
Os scripts executados pelo servidor web serão escritos com a ferramenta NetBeans. Até agora, escrevemos scripts PHP executados em um contexto de console:
![]() |
O usuário utiliza o console para solicitar a execução de um script PHP e receber os resultados.
Nas aplicações cliente/servidor que serão apresentadas a seguir,
- o script do cliente é executado em um contexto de console
- o script do servidor é executado em um contexto web
![]() |
O script PHP do servidor não pode estar em qualquer lugar no sistema de arquivos. Na verdade, o servidor web procura, nos locais especificados pela configuração, os documentos estáticos e dinâmicos que lhe são solicitados. A configuração padrão do WampServer faz com que os documentos sejam procurados na pasta <WampServer>/www, onde <WampServer> é a pasta de instalação do WampServer. Assim, se um cliente web solicitar um documento D com o URL [http://localhost/D], o servidor web fornecerá o documento D do caminho [<WampServer>/www/D].
Nos exemplos a seguir, colocaremos os scripts do servidor na pasta [www/exemples-web]. Se um script do servidor se chamar S.php, ele será solicitado ao servidor web com o URL [http://localhost/exemples-web/S.php]. O documento [<WampServer>/www/exemples-web/S.php] será então fornecido.
![]() |
Para criar um script de servidor com o NetBeans para , procederemos da seguinte maneira:
![]() |
- em [1], criamos um novo projeto
- em [2], selecionamos a categoria [PHP] e o projeto [PHP Application]
![]() |
- em [3], nomeamos o projeto
- em [4], escolhemos uma pasta para o projeto
- em [5], indicamos que o script deve ser executado por um servidor web local (o endereço do script será do tipo http://localhost/...). O servidor web local será o servidor web Apache de WampServer.
- No [6], informamos o URL do projeto. Aqui, decidimos que um script S.php do projeto será solicitado com o URL e o [http://localhost/exemples-web/S.php]. De acordo com o que foi dito, isso significa que o caminho do script S.php no sistema de arquivos será [<WampServer>/www/exemples-web/S.php]. É isso que está indicado em [7]. Solicitamos aqui que todos os scripts S.php do projeto sejam copiados para a árvore de diretórios do servidor web Apache.
- em [8], o novo projeto.
Vamos escrever um script de teste:
![]() |
- em [1], criamos no projeto [exemples-web] um primeiro script PHP
- em [2], atribuímos um nome a ele
- em [3], após criá-lo, inserimos o seguinte conteúdo
Em seguida, é necessário que o WampServer seja executado.
![]() |
- em [4], executamos o script da web [exemple1.php]. O NetBeans, então, abrirá o navegador padrão do computador e solicitará que ele exiba o URL, [http://localhost/exemples-web/exemple1.php] e [5]
- em [6]; o navegador exibe o que o script do servidor enviou ao cliente.
Posteriormente, encontraremos dois tipos de clientes web:
- um navegador como o descrito acima. Mencionamos que o servidor web enviava uma resposta no formato: cabeçalhos HTTP, linha vazia, texto. O navegador exibe apenas texte.
- um script PHP, que exibirá a resposta completa: cabeçalhos HTTP, linha vazia, texto.
A seguir,
- os scripts de servidor serão escritos como [exemple1.php] acima
- os scripts do cliente serão escritos da mesma forma que os scripts de console que escrevemos até agora.
10.1. Aplicativo cliente/servidor de data/hora
10.1.1. O servidor (web_01)
<?php
// tempo: número de milissegundos desde 01/01/1970
// formato de exibição de data e hora
// d: dia com 2 dígitos
// m: mês com 2 dígitos
// y: ano com 2 dígitos
// H: hora 0,23
// i: minutos
// s: segundos
print date("d/m/y H:i:s",time());
Basicamente, o script PHP acima exibe a hora atual na tela. No entanto, quando executado por um servidor web, o fluxo nº 1, que normalmente está associado à tela, é redirecionado para a conexão que liga o servidor ao seu cliente. Portanto, em um contexto da web, o script acima envia a hora atual na forma de texto para o cliente.
Vamos executar esse script no NetBeans:
![]() |
- em [1], executamos o script. Um navegador da web é então iniciado.
- em [2], o URL solicitado pelo navegador da web
- em [3], o texto enviado pelo script do servidor
O navegador do cliente utiliza o protocolo HTTP para se comunicar com o servidor web. Já descrevemos a estrutura desse protocolo.
O cliente envia linhas de texto que podem ser divididas em três partes: cabeçalhos HTTP, linha vazia e documento. O documento enviado ao servidor web geralmente está vazio ou consiste em um conjunto de parâmetros parami=vali, em que vali é um valor inserido pelo usuário em um formulário HTML.
A resposta do servidor tem o mesmo formato: cabeçalhos HTTP, linha vazia, documento, em que document é, desta vez, o documento solicitado pelo navegador do cliente. Se o cliente tiver enviado parâmetros, o documento entregue geralmente depende desses parâmetros.
Com o navegador Firefox, é possível verificar as trocas reais entre o cliente e o servidor web. Existe um complemento para o Firefox, chamado Firebug, que permite rastrear essas trocas. O Firebug está disponível no Firefox. Se usarmos o navegador Firefox para acessar essa URL, poderemos baixar o plug-in Firebug. Supomos, a partir de agora, que o plug-in Firebug foi baixado e instalado. Ele está disponível por meio de uma opção do menu do Firefox:
![]() |
Uma janela do Firebug é aberta na janela do navegador Firefox. Essa janela, por sua vez, apresenta um menu:
![]() |
Para analisar as trocas entre cliente e servidor durante uma solicitação HTTP, fazemos a solicitação URL [http://localhost/exemples-web/web_01.php] usando o navegador Firefox. A janela do Firebug então se preenche com informações:
![]() |
Acima, temos um resumo das trocas cliente/servidor:
- [1]: o cliente enviou o comando HTTP: GET /exemplos-web/web_01.php HTTP/1.1 para solicitar o documento [web01.php]
- [2]: o servidor enviou a resposta: HTTP/1.1 200 OK, indicando que encontrou o documento solicitado.
O Firebug permite visualizar todas as trocas de dados. Basta “expandir” o URL:
![]() |
Vemos acima os cabeçalhos HTTP trocados entre o cliente (Solicitação) e o servidor (Resposta). É possível obter o código-fonte das trocas, c.a.d, e as linhas de texto efetivamente trocadas, [1]. Assim, obtemos o seguinte código-fonte:
![]() |
Para escrever um script de cliente para o servidor web, basta reproduzir o comportamento do navegador. Após estabelecer uma conexão com o servidor, o script de cliente poderia enviar as 8 linhas da solicitação acima. Na verdade, nem tudo é indispensável e enviaremos apenas as três linhas a seguir:
- linha 1: especifica o documento solicitado e o protocolo HTTP utilizado
- linha 2: fornece o nome do computador do script do cliente
- linha 3: indica que, após a troca de dados, o cliente encerrará a conexão com o servidor
Vamos agora nos concentrar na resposta do servidor. Sabemos que ela foi gerada pelo script PHP [web_01.php]. Acima, vemos os cabeçalhos HTTP da resposta. O código do script [web01.php] mostra que não foi ele quem os gerou. Lembremo-nos da configuração do script do servidor:
![]() |
Foi o servidor web que gerou os cabeçalhos HTTP da resposta. O script do servidor pode gerá-los por conta própria. Veremos um exemplo disso um pouco mais adiante.
Dissemos que a resposta do servidor web tinha o seguinte formato: cabeçalhos HTTP, linha vazia, documento. Se o documento for um documento de texto, é possível visualizá-lo na aba [Réponse] do Firebug:
![]() |
Essa resposta foi gerada pelo script [web_01.php].
10.1.2. Um cliente (client1_web_01)
Agora vamos escrever um script de cliente para o serviço anterior. Sabemos que o cliente deve:
- abrir uma conexão com o servidor web
- enviar o texto: cabeçalhos HTTP, linha em branco
- ler a resposta completa do servidor até que este feche a conexão com o cliente
- fechar a conexão com o servidor
O script do cliente é executado em um ambiente de console do NetBeans:
![]() |
- em [1], o script do cliente [client1_web_01.php] está incluído no projeto do NetBeans [exemples]
- em [2], as propriedades do projeto NetBeans [exemples]
- no [3], o projeto NetBeans [exemples] é executado no modo “linha de comando”, que também chamamos de modo “console”.
O código do script do cliente é o seguinte:
<?php
// dados
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_01.php";
// abertura de uma conexão na porta 80 do $HOTE
$connexion = fsockopen($HOTE, $PORT);
// erro?
if (!$connexion) {
print "Erreur : $erreur\n";
exit;
}
// os cabeçalhos (headers) do protocolo HTTP devem terminar com uma linha em branco
// GET
fputs($connexion, "GET $urlServeur HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Conexão
fputs($connexion,"Connection: close\n");
// linha vazia
fputs($connexion,"\n");
// o servidor agora responderá no canal $connexion. Ele enviará todos
// seus dados e, em seguida, fechará o canal. O cliente, portanto, lê tudo o que chega de $connexion
// até o fechamento do canal
while ($ligne = fgets($connexion, 1000)) {
print "$ligne";
}//enquanto
// o cliente, por sua vez, encerra a conexão
fclose($connexion);
// fim
exit;
Comentários
- linha 8: abertura de uma conexão com o servidor
- linha 16: comando HTTP GET
- linha 18: comando HTTP Host
- linha 20: comando HTTP Conexão
- linha 22: linha vazia
- linhas 26-28: leitura de todas as linhas de texto enviadas pelo servidor até que ele feche a conexão.
- linha 30: o cliente, por sua vez, encerra a conexão
Resultados
A execução do script do cliente produz os seguintes resultados:
Comentários
- linhas 1-7: a resposta HTTP do servidor web.
- linha 8: a linha vazia que indica o fim dos cabeçalhos HTTP
- linhas 9 e seguintes: o documento. Aqui, trata-se de um texto simples representando a data e a hora atuais. É o texto gravado pelo script PHP na saída nº 1.
- linha 1: o servidor responde que encontrou o documento solicitado.
- linha 2: data e hora atuais do servidor
- linha 3: identidade do servidor web
- linha 4: indica que o documento a seguir é gerado por um script PHP
- linha 5: número de caracteres do documento
- linha 6: o servidor indica que, após enviar o documento, encerrará a conexão
- linha 7: indica que o documento enviado pelo servidor é um texto no formato HTML. Isso está incorreto neste caso. O documento é um texto sem formatação específica. Quando o documento não é um texto no formato HTML, cabe ao script PHP indicar isso. Não fizemos isso aqui.
10.1.3. Um segundo cliente (client2_web_01)
O cliente anterior exibia tudo o que o servidor web lhe enviava. Na prática, geralmente desconsidera-se os cabeçalhos HTTP da resposta e utiliza-se apenas a parte do documento. Aqui, buscamos recuperar a data e a hora enviadas pelo script do servidor PHP. Vamos recuperar essas informações por meio de uma expressão regular.
<?php
// recuperar as informações enviadas por um servidor web
// dados
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_01.php";
// abertura de uma conexão na porta 80 do $HOTE
$connexion = fsockopen($HOTE, $PORT);
// erro?
if (!$connexion) {
print "Erreur : $erreur\n";
exit;
}
// os cabeçalhos (headers) do protocolo HTTP devem terminar com uma linha em branco
// GET
fputs($connexion, "GET $urlServeur HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Conexão
fputs($connexion,"Connection: close\n");
// linha vazia
fputs($connexion,"\n");
// o servidor passará a responder no canal $connexion. Ele enviará todos
// esses dados e, em seguida, fechará o canal. O cliente, portanto, lê tudo o que chega de $connexion
// até encontrar a linha que procura, no formato dd/mm/aa hh:mm:ss
while ($ligne = fgets($connexion, 1000)) {
print "$ligne";
if (preg_match("/(\d\d)\/(\d\d)\/(\d\d) (\d\d):(\d\d):(\d\d)/", $ligne, $champs)) {
// e recupera os # campos
array_shift($champs); // remove o primeiro elemento da matriz de campos
// recuperam-se os 6 campos em 6 variáveis
list($j, $m, $a, $h, $i, $s) = $champs;
// exibição do resultado
print "\ndateheure=[$j,$m,$a,$h,$i,$s]\n";
}//if
}//enquanto
// o cliente encerra a conexão por sua vez
fclose($connexion);
// fim
exit;
Resultados
10.2. Recuperação pelo servidor dos parâmetros enviados pelo cliente
No protocolo HTTP, um cliente tem duas maneiras de passar parâmetros para o servidor web:
- ele solicita o serviço URL na forma
GET url?param1=val1¶m2=val2¶m3=val3… HTTP/1.0
onde os valores vali devem ser previamente codificados para que determinados caracteres reservados sejam substituídos por seus valores hexadecimais.
- ele solicita o URL do serviço na forma
POST url HTTP/1.0
e, em seguida, entre os cabeçalhos HTTP enviados ao servidor, insere o seguinte cabeçalho:
O restante dos cabeçalhos enviados pelo cliente termina com uma linha vazia. Ele pode então enviar seus dados na forma
onde os valores vali devem, assim como no método GET, ser previamente codificados. O número de caracteres enviados ao servidor deve ser N, sendo que N é o valor declarado no cabeçalho
O script PHP, que recupera os parâmetros parami anteriores enviados pelo cliente, obtém seus valores na tabela:
- $_GET["parami"] para um comando GET
- $_POST["parami"] para um comando POST
10.2.1. O cliente GET (client1_web_02)
O script PHP abaixo envia três parâmetros [nom, prenom, age] ao servidor.
<?php
// cliente: envia nome, sobrenome e idade ao servidor pelo método GET
// dados
$HOTE = "localhost";
$PORT = 80;
$URL = "/exemples-web/web_02.php";
list($prenom, $nom, $age) = array("jean-paul", "de la hûche", 45);
// conexão com o servidor web
$connexion = fsockopen($HOTE, $PORT);
// retorno em caso de erro
if (!$connexion) {
print "Echec de la connexion au site ($HOTE,$PORT) : $erreur";
exit;
}//if
// envio das informações ao servidor PHP
// codificação das informações
$infos = "prenom=" . urlencode(utf8_decode($prenom)) . "&nom=" . urlencode(utf8_decode($nom)) . "&age=" . urlencode("$age");
// monitoramento do console
print "infos envoyées au serveur (GET)=$infos\n";
print "URL demandée=[$URL?$infos]\n\n";
// os cabeçalhos (headers) do protocolo HTTP devem terminar com uma linha em branco
// GET
fputs($connexion, "GET $URL?$infos HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Conexão
fputs($connexion,"Connection: close\n");
// linha vazia
fputs($connexion,"\n");
// o servidor passará a responder no canal $connexion. Ele enviará todas
// seus dados e, em seguida, fechar o canal. O cliente lê tudo o que chega de $connexion até o fechamento do canal
while ($ligne = fgets($connexion, 1000))
print "$ligne";
// o cliente, por sua vez, encerra a conexão
fclose($connexion);
Comentários
- linha 7: URL do script do servidor
- linha 8: os valores dos 3 parâmetros
- linha 10: abertura de uma conexão com o servidor web
- linha 18: codificação dos três parâmetros. Estamos em um script escrito no NetBeans com codificação de caracteres em UTF-8. Portanto, os três valores dos parâmetros da linha 8 são codificados em UTF-8. A função utf8_decode converte essa codificação para ISO-8859-1. Feito isso, eles podem ser codificados para URL. Todos os caracteres não alfabéticos são substituídos por %xx, onde xx é o valor hexadecimal do caractere. Os espaços, por sua vez, são substituídos pelo sinal +.
- linha 24: o URL solicitado é $URL?$infos, onde $infos tem o formato nom=val1&prenom=val2&age=val3.
10.2.2. O servidor (web_02)
O servidor se limita a exibir o que recebe.
<?php
// gestão de erros
ini_set("display_errors", "off");
// recuperação pelo servidor das informações enviadas pelo cliente
// aqui, nome=P&sobrenome=N&idade=A
// essas informações ficam automaticamente disponíveis nas variáveis
// $_GET['prenom'], $_GET['nom'], $_GET['age']
// elas são enviadas de volta ao cliente
// cabeçalho UTF-8
header("Content-Type: text/plain; charset=utf-8");
// parâmetros enviados ao servidor
$prenom = isset($_GET['prenom']) ? $_GET['prenom'] : "";
$nom = isset($_GET['nom']) ? $_GET['nom'] : "";
$age = isset($_GET['age']) ? $_GET['age'] : "";
// resposta ao cliente
$réponse = "informations reçues du client [" .
utf8_encode(htmlspecialchars($prenom, ENT_QUOTES)) .
"," . utf8_encode(htmlspecialchars($nom, ENT_QUOTES)) .
"," . utf8_encode(htmlspecialchars($age, ENT_QUOTES)) . "]\n";
print $réponse;
Comentários
- linha 13: define o cabeçalho HTTP “Content-Type”. Por padrão, o servidor web envia o cabeçalho
, que indica que a resposta é um texto no formato HTML. Aqui, a resposta será um texto sem formatação, com caracteres codificados em UTF-8:
Os cabeçalhos HTTP devem ser enviados antes da resposta do servidor. Portanto, conforme mostrado acima, a chamada da função header deve vir antes de qualquer instrução print.
- linhas 16-18: os três parâmetros são recuperados da tabela $_GET.
- linha 21: constrói-se a sequência de caracteres que será enviada como resposta ao cliente. Alguns caracteres têm significados especiais em HTML e devem ser substituídos por entidades HTML para que sejam exibidos. htmlspecialchars($string) substitui todos esses caracteres por seus equivalentes na sequência $string. Por exemplo, o caractere $ torna-se &. Como dissemos na linha 13 que a resposta seria o texto UTF-8, codificamos os valores recuperados em UTF-8.
- linha 25: a resposta é enviada ao cliente
Teste 1
Vamos executar o script [web_02] a partir do NetBeans. Um navegador é então aberto para exibir o URL [http://localhost/exemples-web/web_02.php]:
![]() |
- no [1], o navegador exibe o URL [http://localhost/exemples-web/web_02.php]. Como não adicionamos parâmetros ao final dessa URL, o servidor respondeu com parâmetros vazios. Vale lembrar que a resposta do servidor é aquela gravada com a instrução print.
- Em [2], acrescentamos parâmetros ao URL. Desta vez, o script do servidor os retorna corretamente.
Vale ressaltar que o NetBeans não é necessário para a execução de um script de servidor. Basta digitar o URL do script de servidor em um navegador para que ele seja executado.
Teste 2
Executamos no NetBeans o cliente [client1_web_02.php]. Recebemos a seguinte resposta:
- linha 1: codificação dos 3 parâmetros. Observa-se que o caractere û se tornou %FB.
- linha 12: a resposta do servidor
10.2.3. O cliente POST (client2_web_03)
Um cliente HTTP envia ao servidor web a seguinte sequência de texto: cabeçalhos HTTP, linha vazia, documento. No cliente anterior, essa sequência era a seguinte:
Não havia documento. Existe outra maneira de transmitir parâmetros, o método denominado POST. Nesse caso, a sequência de texto enviada ao servidor web é a seguinte:
Desta vez, os parâmetros que, no cliente GET, estavam incluídos nos cabeçalhos HTTP, fazem parte, no cliente POST, do documento enviado após os cabeçalhos.
O script do cliente POST é o seguinte:
<?php
// cliente: envia nome, sobrenome e idade ao servidor pelo método POST
// dados
$HOTE = "localhost";
$PORT = 80;
$URL = "/exemples-web/web_03.php";
list($prenom, $nom, $age) = array("jean-paul", "de la hûche", 45);
// conexão com o servidor web
$connexion = fsockopen($HOTE, $PORT);
// retorno em caso de erro
if (!$connexion) {
print "Echec de la connexion au site ($HOTE,$PORT) : $erreur";
exit;
}//if
// envio das informações ao servidor PHP
// codificação das informações
$infos = "prenom=" . urlencode(utf8_decode($prenom)) . "&nom=" . urlencode(utf8_decode($nom)) . "&age=" . urlencode("$age");
print "client : infos envoyées au serveur (POST) : $infos\n";
// conectamos-nos ao URL $URL enviando-lhe (POST) parâmetros
// os cabeçalhos (headers) do protocolo HTTP devem terminar com uma linha em branco
// POST
fputs($connexion, "POST $URL HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Conexão
fputs($connexion,"Connection: close\n");
// Content-type
fputs($connexion, "Content-type: application/x-www-form-urlencoded\n");
// Content-length
// envia-se o tamanho (número de caracteres) das informações que serão enviadas
fputs($connexion, "Content-length: " . strlen($infos) . "\n");
// envia-se uma linha vazia
fputs($connexion, "\n");
// envia-se as informações
fputs($connexion, $infos);
// o servidor agora responderá no canal $connexion. Ele enviará todos
// seus dados e, em seguida, fechará o canal. O cliente lê tudo o que chega de $connexion
// até o fechamento do canal
while ($ligne = fgets($connexion, 1000))
print "$ligne";
// o cliente, por sua vez, encerra a conexão
fclose($connexion);
Comentários
- linha 7: o URL do serviço web ao qual o cliente POST se conectará. Esse serviço web será descrito a seguir.
- linha 8: os parâmetros a serem transmitidos ao serviço web
- linha 10: conexão com o servidor web
- linha 18: codificação dos parâmetros a serem enviados ao serviço web
- linha 23: comando HTTP POST
- linha 25: comando HTTP Host
- linha 27: comando HTTP Connection
- linha 29: comando HTTP Content-type. Já encontramos esse cabeçalho HTTP. Ele está presente sempre que um documento é enviado. Um servidor web que envia um documento HTML usa o cabeçalho HTTP
Se enviar texto sem formatação, ele usa o cabeçalho HTTP
Nosso cliente POST envia um documento que é um texto no formato param1=val1¶m2=val2&.... Esse tipo de documento tem o tipo application/x-www-form-urlencoded. Não explicaremos o motivo, pois isso nos obrigaria a explicar o que é um formulário da web.
- linha 32: comando Content-length. Já encontramos esse cabeçalho HTTP. Ele está presente sempre que um documento é enviado. Ele indica o número de bytes do documento.
- linha 34: a linha vazia que sinaliza o fim dos cabeçalhos HTTP
- linha 36: envio dos parâmetros
- linhas 40-41: leitura da resposta completa do servidor
- linha 43: encerramento da conexão
10.2.4. O servidor (web_03)
O serviço web [web_03] faz o mesmo que o serviço web [web_02]. Ele lê os parâmetros enviados pelo cliente POST e os reenvia ao cliente. Seu código é o seguinte:
<?php
// gerenciamento de erros
ini_set("display_errors", "off");
// cabeçalho UTF-8
header("Content-Type: text/plain; charset=utf-8");
// recuperação pelo servidor das informações enviadas pelo cliente
// aqui, nome=P&sobrenome=N&idade=A
// essas informações ficam automaticamente disponíveis nas variáveis
// $_POST['prenom'], $_POST['nom'], $_POST['age']
// e são reenviadas ao cliente
// parâmetros enviados ao servidor
$prenom = isset($_POST['prenom']) ? $_POST['prenom'] : "";
$nom = isset($_POST['nom']) ? $_POST['nom'] : "";
$age = isset($_POST['age']) ? $_POST['age'] : "";
// resposta ao cliente
$réponse = "informations reçues du client [" .
utf8_encode(htmlspecialchars($prenom, ENT_QUOTES)) .
"," . utf8_encode(htmlspecialchars($nom, ENT_QUOTES)) .
"," . utf8_encode(htmlspecialchars($age, ENT_QUOTES)) . "]\n";
print $réponse;
Comentários
- linhas 14-16: os parâmetros enviados por um cliente POST ficam disponíveis na matriz $_POST para o serviço web que os recebe.
- linha 6: cabeçalho HTTP Content-Type. Pode ser surpreendente não encontrar nos cabeçalhos HTTP o cabeçalho HTTP Content-Length, que indica o tamanho do documento enviado de volta ao cliente. Vimos que o servidor web enviava cabeçalhos HTTP por padrão. O cabeçalho Content-Length faz parte deles.
Resultados
Depois que o script do servidor é escrito no NetBeans, ele fica imediatamente disponível através do servidor Apache com o cabeçalho WampServer. Vale lembrar que isso é obtido por meio de configuração (ver parágrafo 10). Iniciamos o cliente, que consulta o servidor, e recebemos então a seguinte resposta:
- linhas 2-10: a resposta do servidor
- linhas 2-8: os cabeçalhos HTTP
- linha 10: o documento
- linha 6: o cabeçalho HTTP Content-Length. Como não foi o script do servidor que gerou esse cabeçalho, ele foi, portanto, gerado pelo servidor web.
- linha 8: o único cabeçalho gerado pelo script do servidor
10.3. Recuperação das variáveis de ambiente do servidor WEB
Um script de servidor é executado em um ambiente web que ele pode reconhecer. Esse ambiente está armazenado no dicionário $_SERVER. Primeiramente, escrevemos um aplicativo de servidor que envia aos seus clientes o conteúdo desse dicionário.
10.3.1. O servidor (web_04)
<?php
// gestão de erros
ini_set("display_errors", "off");
// cabeçalho UTF-8
header("Content-Type: text/plain; charset=utf-8");
// envia-se ao cliente a lista de variáveis disponíveis no ambiente do servidor
foreach ($_SERVER as $clé => $valeur) {
print "[$clé,$valeur]\n";
}
- os pares (chave, valor) do dicionário $_SERVER são enviados aos clientes.
O resultado obtido quando o cliente é um navegador da web é o seguinte:

Aqui está o significado de algumas das variáveis (para Windows. No Linux, elas seriam diferentes):
CMDE representa o cabeçalho HTTP enviado pelo cliente. Temos acesso a todos esses cabeçalhos. | |
o caminho dos executáveis na máquina na qual o script do servidor está sendo executado | |
o caminho do interpretador de comandos do DOS | |
as extensões dos arquivos executáveis | |
a pasta de instalação do Windows | |
a assinatura do servidor web. Aqui não há nada. | |
o tipo do servidor web | |
o nome de Internet da máquina do servidor web | |
a porta de escuta do servidor web | |
o endereço IP do servidor web | |
o endereço IP do cliente. Neste caso, o cliente estava na mesma máquina que o servidor. | |
a porta de comunicação do cliente | |
a raiz da árvore de documentos servidos pelo servidor web | |
o endereço de e-mail do administrador do servidor web | |
o caminho completo do script do servidor | |
a versão do protocolo HTTP utilizada pelo servidor web | |
o comando HTTP utilizado pelo cliente. Existem quatro: GET, POST, PUT, DELETE | |
os parâmetros enviados com uma ordem GET /url?parâmetros | |
o URL solicitado pelo cliente. Se o navegador solicitar o URL http://machine[:port]/uri, teremos REQUEST_URI=uri | |
$_SERVER['SCRIPT_FILENAME']=$_SERVER['DOCUMENT_ROOT'].$_SERVER['SCRIPT_NAME'] |
10.3.2. O cliente (client1_web_04)
O cliente se limita a exibir tudo o que o servidor lhe envia.
<?php
// dados
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_04.php";
// abertura de uma conexão na porta 80 do $HOTE
$connexion = fsockopen($HOTE, $PORT);
// erro?
if (!$connexion) {
print "Erreur : $erreur\n";
exit;
}
// conectando-se a um URL no servidor web
// os cabeçalhos (headers) do protocolo HTTP devem terminar com uma linha em branco
// GET
fputs($connexion, "GET $urlServeur HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Conexão
fputs($connexion,"Connection: close\n");
// linha vazia
fputs($connexion,"\n");
// o servidor agora responderá no canal $connexion. Ele enviará todos
// seus dados e, em seguida, fechará o canal. O cliente, portanto, lê tudo o que chega de $connexion
// até o fechamento do canal
while ($ligne = fgets($connexion, 1000)) {
print "$ligne";
}//enquanto
// o cliente, por sua vez, encerra a conexão
fclose($connexion);
// fim
exit;
Resultados
10.4. Gerenciamento de sessões WEB
Nos exemplos de cliente/servidor anteriores, o funcionamento era o seguinte:
- o cliente abre uma conexão com a porta 80 do servidor do serviço web
- ele envia a sequência de texto: cabeçalhos HTTP, linha em branco, [document]
- em resposta, o servidor envia uma sequência do mesmo tipo
- o servidor encerra a conexão com o cliente
- o cliente encerra a conexão com o servidor
Se o mesmo cliente fizer, pouco depois, uma nova solicitação ao servidor web, uma nova conexão é criada entre o cliente e o servidor. O servidor não tem como saber se o cliente que está se conectando já acessou o servidor anteriormente ou se esta é a primeira solicitação. Entre duas conexões, o servidor “esquece” seu cliente. Por esse motivo, diz-se que o protocolo HTTP é um protocolo sem estado. No entanto, é útil que o servidor se lembre de seus clientes. Assim, se um aplicativo for seguro, o cliente enviará ao servidor um nome de usuário e uma senha para se identificar. Se o servidor “esquecer” seu cliente entre duas conexões, este terá que se identificar a cada nova conexão, o que não é viável.
Para acompanhar um cliente, o servidor procede da seguinte maneira: durante a primeira solicitação de um cliente, ele inclui em sua resposta um identificador que o cliente deve, então, reenviar a cada nova solicitação. Graças a esse identificador, diferente para cada cliente, o servidor pode reconhecer um cliente. Ele pode, então, gerenciar uma memória para esse cliente na forma de um arquivo associado de maneira única ao identificador do cliente.
Tecnicamente, isso ocorre da seguinte forma:
- na resposta a um novo cliente, o servidor inclui o cabeçalho HTTP Set-Cookie: MotClé=Identificador. Ele faz isso apenas na primeira solicitação.
- Em suas solicitações seguintes, o cliente enviará seu identificador por meio do cabeçalho HTTP Cookie: MotClé=Identificador, para que o servidor o reconheça.
Pode-se perguntar como o servidor sabe que está lidando com um novo cliente, em vez de um cliente que já visitou o site anteriormente. É a presença do cabeçalho HTTP Cookie nos cabeçalhos HTTP do cliente que indica isso ao servidor. Para um novo cliente, esse cabeçalho está ausente.
O conjunto de conexões de um determinado cliente é chamado de sessão.
10.4.1. O arquivo de configuração
Para que o gerenciamento de sessões funcione corretamente com o PHP, é necessário verificar se ele está configurado corretamente. No Windows, seu arquivo de configuração é o PHP.ini. Dependendo do contexto de execução (console, web), o arquivo de configuração [PHP.ini] deve ser procurado em pastas diferentes. Para identificá-las, utilize-se o seguinte script:
Na linha 4, a função phpinfo fornece informações sobre o interpretador PHP que executa o script. Ela fornece, em particular, o caminho do arquivo de configuração [PHP.ini] utilizado.
Em um ambiente de console, obtém-se um resultado semelhante ao seguinte:
linha 2: o arquivo de configuração principal é c:\windows\PHP.ini
linha 3: um arquivo de configuração secundário é C:\serveursSGBD\wamp21\bin\PHP\php5.3.5\PHP.ini. Ele permite alterar algumas opções de configuração do arquivo de configuração principal.
Em um ambiente web, obtém-se o seguinte resultado:

O arquivo de configuração secundário aqui não é o mesmo que no ambiente de console. É este último que vamos consultar. Neste arquivo, encontramos uma seção chamada “session”:
- linha 1: os dados de uma sessão do cliente são salvos em um arquivo
- linha 3: a pasta de armazenamento dos dados da sessão. Se essa pasta não existir, nenhum erro será sinalizado e o gerenciamento de sessões não funcionará.
- linhas 4-5: indicam que o identificador de sessão é gerenciado pelos cabeçalhos HTTP Set-Cookie e Cookie
- linha 6: o cabeçalho Set-Cookie terá o formato Set-Cookie: PHPSESSID=identifiant_de_session
- linha 7: uma sessão do cliente não é iniciada automaticamente. O script do servidor deve solicitá-la explicitamente por meio da instrução session_start().
10.4.2. O servidor 1 (web_05)
O gerenciamento do identificador de sessão é transparente para um serviço web. Esse identificador é gerenciado pelo servidor web. Um serviço web tem acesso à sessão do cliente por meio da instrução session_start(). A partir desse momento, o serviço web pode ler/gravar dados na sessão do cliente por meio do dicionário $_SESSION. O código a seguir mostra o gerenciamento de três contadores na sessão.
<?php
// gerenciamento de erros
ini_set("display_errors", "off");
// cabeçalho UTF-8
header("Content-Type: text/plain; charset=utf-8");
// iniciando sessão
session_start();
// colocamos 3 variáveis na sessão
if (!isset($_SESSION['N1'])) {
$_SESSION['N1'] = 0;
}
if (!isset($_SESSION['N2'])) {
$_SESSION['N2'] = 10;
}
if (!isset($_SESSION['N3'])) {
$_SESSION['N3'] = 100;
}
// incremento das 3 variáveis
$_SESSION['N1']++;
$_SESSION['N2']++;
$_SESSION['N3']++;
// envio de informações ao cliente
print "N1=".$_SESSION['N1']."\n";
print "N2=".$_SESSION['N2']."\n";
print "N3=".$_SESSION['N3']."\n";
// fim da sessão
session_close();
- linha 9: início de uma sessão do cliente
- linhas 11-13: o array $_SESSION é um dicionário de pares (chave, valor). Os dados inseridos nesse dicionário persistem ao longo das solicitações de um mesmo cliente. Trata-se da memória do cliente no servidor.
- linhas 11-19: se os três contadores N1, N2 e N3 não estiverem na sessão, eles são inseridos nela.
- linhas 21-23: eles são incrementados em uma unidade
- linhas 25-27: enviamos seus valores para o cliente
Na relação cliente/servidor, o gerenciamento da sessão do cliente no servidor depende dos dois participantes, o cliente e o servidor:
- o servidor é responsável por enviar um identificador ao cliente na primeira solicitação
- o cliente é responsável por reenviar esse identificador a cada nova solicitação. Se não o fizer, o servidor considerará que se trata de um novo cliente e gerará um novo identificador para uma nova sessão.
Resultados
Usamos como cliente um navegador da web. Por padrão (na verdade, por configuração), ele reenvia ao servidor os identificadores de sessão que este lhe envia. À medida que as solicitações são feitas, o navegador receberá os três contadores enviados pelo servidor e verá seus valores serem incrementados.
![]() |
- em [1], a primeira solicitação ao serviço web [web_05]
- para [2]; a terceira solicitação mostra que os contadores foram incrementados corretamente. Os valores dos contadores são, de fato, memorizados ao longo das solicitações.
Vamos usar o Firebug para ver os cabeçalhos HTTP trocados entre o servidor e o cliente. Fechamos o Firefox para encerrar a sessão atual com o servidor, reabrimos o navegador e ativamos o Firebug. Solicitamos o serviço |web_05]:
![]() |
Acima, vemos o identificador de sessão enviado pelo servidor em sua resposta à primeira solicitação do cliente. Ele utiliza o cabeçalho HTTP Set-Cookie.
Vamos fazer uma nova solicitação atualizando (F5) a página no navegador da web:
![]() |
Acima, observamos duas coisas:
- o navegador retorna o identificador de sessão com o cabeçalho HTTP Cookie.
- em sua resposta, o serviço web não inclui mais esse identificador. Agora, cabe ao cliente enviá-lo em cada uma de suas solicitações.
10.4.3. O cliente 1 (client1_web_05)
Agora, vamos escrever um script de cliente baseado no script de servidor anterior. Em sua gestão da sessão, ele deve se comportar como um navegador da web:
- Na resposta do servidor à sua primeira solicitação, ele deve encontrar o identificador de sessão que o servidor lhe envia. Ele sabe que o encontrará no cabeçalho HTTP Set-Cookie.
- Em cada uma de suas solicitações subsequentes, ele deve reenviar ao servidor o identificador que recebeu. Ele fará isso com o cabeçalho HTTP Cookie.
O código do cliente é o seguinte:
<?php
// dados
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_05.php";
// testes
$cookie = "";
for ($i = 0; $i < 5; $i++) {
list($erreur, $cookie, $N1, $N2, $N3) = connecte($HOTE, $PORT, $urlServeur, $cookie);
print "----------------------------\n";
print "client(erreur,cookie,N1,N2,N3)=[$erreur,$cookie,$N1,$N2,$N3]\n";
print "----------------------------\n";
}
// fim
exit;
function connecte($HOTE, $PORT, $urlServeur, $cookie) {
// conecta o cliente a ($HOTE,$PORT,$urlServeur)
// envia o cookie $cookie se ele não estiver vazio
// exibe todas as linhas recebidas como resposta
// abertura de uma conexão na porta 80 do $HOTE
$connexion = fsockopen($HOTE, $PORT);
// erro?
if (!$connexion)
return array("erreur lors de la connexion au serveur ($HOTE, $PORT)");
// conectando-se ao $urlserveur
// os cabeçalhos (headers) do protocolo HTTP devem terminar com uma linha em branco
// GET
fputs($connexion, "GET $urlServeur HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Conexão
fputs($connexion, "Connection: close\n");
// o cookie é enviado se não estiver vazio
if ($cookie) {
fputs($connexion, "Cookie: $cookie\n");
}//se
// envio de linha vazia
fputs($connexion, "\n");
// exibe-se a resposta do servidor web
// e nos certificamos de recuperar o eventual cookie e os valores dos Ni
$N = "";
while ($ligne = fgets($connexion, 1000)) {
print "$ligne";
// cookie — somente na primeira resposta
if (!$cookie) {
if (preg_match("/^Set-Cookie: (.*?)\s*$/", $ligne, $champs)) {
$cookie = $champs[1];
}
}
// valor de N1
if (preg_match("/^N1=(.*?)\s*$/", $ligne, $champs))
$N1 = $champs[1];
// valor de N2
if (preg_match("/^N2=(.*?)\s*$/", $ligne, $champs))
$N2 = $champs[1];
// valor de N3
if (preg_match("/^N3=(.*?)\s*$/", $ligne, $champs))
$N3 = $champs[1];
}//enquanto
// a conexão é encerrada
fclose($connexion);
// retorno
return array("", $cookie, $N1, $N2, $N3);
}
Comentários
- linhas 3-16: o programa principal
- linhas 18-67: a função connecte
- linhas 9-14: o cliente chama o servidor 5 vezes e exibe os valores sucessivos dos contadores N1, N2 e N3. Se a sessão for gerenciada corretamente, esses contadores devem ser incrementados em 1 a cada nova solicitação.
- linha 10: a função connecte utiliza os parâmetros $HOTE, $PORT e $urlServeur para conectar o cliente ao serviço web. O parâmetro $cookie representa o identificador de sessão. Na primeira chamada, é uma string vazia. Nas chamadas seguintes, é o identificador de sessão enviado pelo servidor em resposta à primeira chamada do cliente. A função connecte retorna, como resultados, os valores dos três contadores $N1, $N2, $N3, o identificador de sessão $cookie e um possível erro $erreur.
- linha 18: a função connecte apresenta as características de um cliente HTTP clássico. Comentamos apenas as novidades.
- linhas 30-40: envio dos cabeçalhos HTTP.
- linhas 36-38: se o identificador de sessão for conhecido, ele é enviado ao servidor
- linhas 44-66: processamento de todas as linhas de texto enviadas pelo servidor
- linhas 47-51: se o identificador de sessão ainda não tiver sido recuperado, ele é recuperado no cabeçalho HTTP Set-Cookie por meio de uma expressão regular.
- linhas 53-54: o contador N1 também é obtido por meio de uma expressão regular
- linhas 56-57, 59-60: o mesmo vale para os contadores N2 e N3
- linha 63: encerramento da conexão com o servidor.
- linha 65: retorno dos resultados na forma de uma tabela.
Resultados
A execução do script do cliente gera a seguinte exibição no console do NetBeans:
- linha 5: em sua primeira resposta, o servidor envia o identificador de sessão. Nas respostas seguintes, ele não o envia mais.
- Percebe-se claramente que o servidor Web mantém os valores de (N1, N2, N3) ao longo das solicitações do cliente. Isso é chamado de rastreamento de sessão.
Os dois exemplos a seguir mostram que também é possível salvar os valores de um array ou de um objeto.
10.4.4. O servidor 2 (web_06)
O script de servidor a seguir mostra que é possível armazenar um array ou um dicionário na sessão.
<?php
// gerenciamento de erros
ini_set("display_errors", "off");
// cabeçalho UTF-8
header("Content-Type: text/plain; charset=utf-8");
// iniciando sessão
session_start();
// gravando um array e um dicionário
// inicializa-se ou modifica-se o array
if (isset($_SESSION['tableau'])) {
for ($i = 0; $i < count($_SESSION['tableau']); $i++) {
$_SESSION['tableau'][$i]++;
}
} else {
for ($i = 0; $i < 10; $i++) {
$_SESSION['tableau'][$i] = $i * 10;
}
}
// inicializa-se ou modifica-se o dicionário
if (isset($_SESSION['dico'])) {
foreach (array_keys($_SESSION['dico']) as $clé) {
$_SESSION['dico'][$clé]++;
}
} else {
$_SESSION['dico'] = array("zéro" => 0, "dix" => 10, "vingt" => 20);
}
// envio de informações ao cliente
print "tableau=" . join(",", $_SESSION['tableau']) . "\n";
print "dico=";
foreach ($_SESSION['dico'] as $clé => $valeur) {
print "($clé,$valeur) ";
}
print "\n";
Comentários
- linhas 17-19: um array é inicialmente inserido na sessão, caso ainda não esteja nela
- linhas 12-15: se já estiver na sessão, seus elementos são incrementados em 1
- linha 27: um dicionário com valores numéricos é inserido na sessão, caso ainda não esteja nela
- linhas 22-25: se já estiver na sessão, seus valores numéricos são incrementados em 1
- linhas 30-35: o array e o dicionário são enviados ao cliente
10.4.5. O cliente 2 (client1_web_06)
<?php
// dados
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_06.php";
// testes
$cookie = "";
for ($i = 0; $i < 5; $i++) {
connecte($HOTE, $PORT, $urlServeur, $cookie);
}
// fim
exit;
function connecte($HOTE, $PORT, $urlServeur, &$cookie) {
// conecta o cliente a ($HOTE, $PORT, $urlServeur)
// envia o cookie $cookie se ele não estiver vazio
// exibe todas as linhas recebidas na resposta
// o cookie é passado por referência para ser compartilhado entre
// o programa chamado e o programa chamador
// abertura de uma conexão na porta $PORT de $HOTE
$connexion = fsockopen($HOTE, $PORT);
// erro?
if (!$connexion)
return array("erreur lors de la connexion au serveur ($HOTE, $PORT)");
// os cabeçalhos (headers) do protocolo HTTP devem terminar com uma linha em branco
// GET
fputs($connexion, "GET $urlServeur HTTP/1.1\n");
// Host
fputs($connexion, "Host: localhost\n");
// Conexão
fputs($connexion, "Connection: close\n");
// o cookie é enviado se não estiver vazio
if ($cookie) {
fputs($connexion, "Cookie: $cookie\n");
}
// envio de linha vazia
fputs($connexion, "\n");
// exibe-se a resposta do servidor web
// e nos certificamos de recuperar o eventual cookie
while ($ligne = fgets($connexion, 1000)) {
print "$ligne";
// cookie — somente na primeira resposta
if (!$cookie) {
if (preg_match("/^Set-Cookie: (.*?)\s*$/", $ligne, $champs)) {
$cookie = $champs[1];
}
}
}
// encerra-se a conexão
fclose($connexion);
// retorno
return "";
}
O código do cliente é semelhante ao código do cliente já comentado.
Resultados
10.4.6. O servidor 3 (web_07)
O script de servidor a seguir mostra que é possível colocar um objeto na sessão.
<?php
// gestão de erros
ini_set("display_errors", "off");
// cabeçalho UTF-8
header("Content-Type: text/plain; charset=utf-8");
// inicia-se uma sessão
session_start();
// inicialização ou modificação de um objeto Pessoa
if (isset($_SESSION['personne'])) {
$personne = $_SESSION['personne'];
// incrementa-se a idade
$personne->setAge($personne->getAge() + 1);
} else {
// define-se a pessoa
$_SESSION['personne'] = new Personne("paul", "langévin", 10);
}
// exibição para o cliente
print "personne=".$_SESSION['personne']."\n";
// fim
exit;
// ----------------------------------------------------------------
class Personne {
// atributos da classe
private $prénom;
private $nom;
private $âge;
// getters e setters
public function getPrénom() {
return $this->prénom;
}
public function getNom() {
return $this->nom;
}
public function getAge() {
return $this->âge;
}
public function setPrénom($prénom) {
$this->prénom = $prénom;
}
public function setNom($nom) {
$this->nom = $nom;
}
public function setAge($age) {
$this->âge = $age;
}
// construtor
function __construct($prénom, $nom, $âge) {
// passamos pelos set
$this->setPrénom($prénom);
$this->setNom($nom);
$this->setAge($âge);
}
// método toString
function __toString() {
return "[$this->prénom,$this->nom,$this->âge]";
}
}
Comentários
- linha 17: coloca-se um objeto do tipo Personne na sessão, caso ele ainda não esteja lá.
- linhas 11-15: se ele já estiver na sessão, aumenta-se sua idade em 1
- linha 20: o objeto do tipo Personne é enviado ao cliente.
10.4.7. O cliente 3 (client1_web_07)
<?php
// dados
$HOTE = "localhost";
$PORT = 80;
$urlServeur = "/exemples-web/web_07.php";
// testes
$cookie = "";
for ($i = 0; $i < 5; $i++) {
connecte($HOTE, $PORT, $urlServeur, $cookie);
}//if
// fim
exit;
function connecte($HOTE, $PORT, $urlServeur, &$cookie) {
...
}
Comentários
- linha 15: a função connecte é idêntica à do script do cliente anterior
Resultados




















