Manejo de XForms

Anuncio
Características
Autenticación HTTP con PHP
Es posible usar la función header() para enviar un mensaje "Authentication Required" al
navegador del cliente causando que se abra una ventana para ingresar usuario y password. Una vez
se ha llenado el usuario y password, la URL contenida dentro del script PHP será llamada nuevamente
con las variables predefinidas PHP_AUTH_USER, PHP_AUTH_PW, y AUTH_TYPE puestas por el nombre
del usuario, password y el tipo de autenticación respectivamente. Esas variables predefinidas son
encontradas en los arrays $_SERVER y $HTTP_SERVER_VARS. Ambos métodos de autenticación
"Basic" y "Digest" (desde PHP 5.1.0) son soportados. Ver la función header() para más información.
Nota: Nota de la versión de PHP
Superglobals, como $_SERVER, están disponibles en PHP » 4.1.0.
Un fragmento de ejemplo de un script el cual podría forzar la autenticación en una página es el
siguiente:
Ejemplo #1 Ejemplo de Autenticación HTTP Basic
<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
header('WWW-Authenticate: Basic realm="My Realm"');
header('HTTP/1.0 401 Unauthorized');
echo 'Texto a enviar si el usuario pulsa el botón Cancelar';
exit;
} else {
echo "<p>Hola {$_SERVER['PHP_AUTH_USER']}.</p>";
echo "<p>Tu ingresaste {$_SERVER['PHP_AUTH_PW']} como tu password.</p>";
}
?>
Ejemplo #2 Ejemplo de Autenticación HTTP Digest
Este ejemplo muestra como implementar un script PHP de autenticación Digest. Para más
información leer » RFC 2617.
<?php
$realm = 'Area restringida';
//user => password
$users = array('admin' => 'mypass', 'guest' => 'guest');
if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="'.$realm.
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
die('Texto a enviar si el usuario pulsa el botón Cancelar');
}
// analiza la variable PHP_AUTH_DIGEST
if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) ||
!isset($users[$data['username']]))
die('Datos Erroneos!');
// Generando una respuesta valida
$A1 = md5($data['username'] . ':' . $realm . ':' . $users[$data['username']]);
$A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
$valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].
':'.$A2);
if ($data['response'] != $valid_response)
die('Datos Erroneos!');
// ok, usuario & password validos
echo 'Estas logueado como: ' . $data['username'];
// function to parse the http auth header
function http_digest_parse($txt)
{
// proteger contra datos perdidos
$needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 're
sponse'=>1);
$data = array();
$keys = implode('|', array_keys($needed_parts));
preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $txt, $matches, PREG_SET_
ORDER);
foreach ($matches as $m) {
$data[$m[1]] = $m[3] ? $m[3] : $m[4];
unset($needed_parts[$m[1]]);
}
return $needed_parts ? false : $data;
}
?>
Nota: Nota de Compatibilidad
Hay que ser cuidadoso cuando se programan las líneas del HTTP header. Para garantizar la mayor
compatibilidad con todos los clientes, la palabra "Basic" debe ser escrita con mayúsculas "B", el string
real debe ser encerrado en comillas dobles (no simples), y exactamente un espacio debe preceder el
código401 en la línea del header HTTP/1.0 401. Los parámetros de autenticación deben ser
separados por comas como se vió en el ejemplo resumido anterior.
En lugar de imprimir simplemente PHP_AUTH_USER y PHP_AUTH_PW, como se hizo en el ejemplo
anterior, se debería chequear el usuario y password para validar. Talvez enviando una consulta a una
base de datos, o buscando el usuario en un archivo dbm.
Cuidado con errores con el Internet Explorer. Parece ser muy quisquilloso con el orden de los
headers. Enviando el header WWW-Authenticate antes que el header HTTP/1.0 401 parece ser
un truco por ahora.
A partir de PHP 4.3.0, en orden de prevenir que alguien escriba un script el cual revele el password
para una página que fué autenticada con un mecanismo externo tradicional, las variables PHP_AUTH
no deberán ser colocadas si la autenticación externa esta habilitada para esa página en particular y
si safe modeesta habilitado. Independientemente, REMOTE_USER puede ser usado para identificar al
usuario autenticado externamente. Así, se podrá usar$_SERVER['REMOTE_USER'].
Nota: Nota de configuración
PHP usa la presencia de una directiva AuthType para determinar si una autenticación externa esta
en uso.
Nótese, sin embargo, que lo anterior no impide que alguien quien controle una URL no autenticada
pueda robar passwords de URL's autenticadas en el mismo servidor.
Tanto Netscape Navigator e Internet Explorer borrarán el caché de la ventana de autenticación del
navegador local después de recibr una respuesta 401. Esto puede "desloguear" efectivamente a un
usuario, forzandolo a reingresar su usuario y password. Algunas personas usan esto para "hacer
esperar" logueos, o proveer un botón de "deslogueo".
Ejemplo #3 Ejemplo de Autenticación HTTP forzando a un nuevo usuario/password
<?php
function authenticate() {
header('WWW-Authenticate: Basic realm="Test Authentication System"');
header('HTTP/1.0 401 Unauthorized');
echo "Debes ingresar un login ID y password validos para accesar a este recurso\n";
exit;
}
if (!isset($_SERVER['PHP_AUTH_USER']) ||
($_POST['SeenBefore'] == 1 && $_POST['OldAuth'] == $_SERVER['PHP_AUTH_USER'])) {
authenticate();
} else {
echo "<p>Bienvenido: " . htmlspecialchars($_SERVER['PHP_AUTH_USER']) . "<br />";
echo "Anterior: " . htmlspecialchars($_REQUEST['OldAuth']);
echo "<form action='' method='post'>\n";
echo "<input type='hidden' name='SeenBefore' value='1' />\n";
echo "<input type='hidden' name='OldAuth' value=\"" . htmlspecialchars($_SERVER['PHP_AUTH_USER
']) . "\" />\n";
echo "<input type='submit' value='Re Authenticate' />\n";
echo "</form></p>\n";
}
?>
Este comportamiento no es requerido por la autenticación HTTP Basic estandar, así que se debería
depender de esto. Probando con Lynx mostrará que Lynxno limpia las credenciales de autenticación
con una respuesta 401 del servidor, asi que presionando back y luego forward abrirá el recurso
nuevamente si estos no han cambiado. Sin embarogo, el usuario puede presionar la tecla '_' para
limpiar su información de autenticación.
También notese que hasta PHP 4.3.3, la autenticación HTTP no trabajaba usando Microsoft IIS con la
versión CGI de PHP, una limitación de IIS. Para hacer funcionar PHP 4.3.3 o mayor, se debe editar la
configuracion de IIS "Directory Security". Hacer click en "Edit" y solo chequear "Anonymous
Access", todos los demas campos dejarlos sin chequear.
Otra limitación si se esta usando el módulo IIS (ISAPI) y PHP 4, no se debería usar las
variables PHP_AUTH_* pero en su lugar, la variableHTTP_AUTHORIZATION esta disponible. Por
ejemplo, considerar el siguiente código: list($user, $pw) = explode(':',
base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
Manejo de XForms
» XForms define una variación de los webforms tradicionales los cuales permiten ser usados en una
gran variedad de plataformas y navegadores o inclusive en medios no tradicionales como los
documentos PDF.
La primera diferencia clave con XForms es la forma en que los formularios son enviados al
cliente. » XForms for HTML Authors contiene una descripción detallada de como crear XForms,
para el fin de este tutorial únicamente veremos un ejemplo simple.
Ejemplo #1 Un formulario simple de búsqueda con XForms
<h:html xmlns:h="http://www.w3.org/1999/xhtml"
xmlns="http://www.w3.org/2002/xforms">
<h:head>
<h:title>Search</h:title>
<model>
<submission action="http://example.com/search"
method="post" id="s"/>
</model>
</h:head>
<h:body>
<h:p>
<input ref="q"><label>Find</label></input>
<submit submission="s"><label>Go</label></submit>
</h:p>
</h:body>
</h:html>
El formulario anterior muestra una caja de texto (llamada q), y un botón submit. Cuando el botón
submit es presionado, el formulario será enviado a la página referenciada por action.
Aquí es donde comienza a verse diferente desde el punto de vista de la aplicación web. En un
formulario normal HTML, los datos serían enviados comoapplication/x-www-form-urlencoded, en
el mundo XForms, esta información es enviada como datos formateados enXML.
Si se ha elegido trabajar con XForms, entonces probablemente se quiera esos datos como XML, en
ese caso, ver en $HTTP_RAW_POST_DATA donde se puede encontrar el XML generado por el
navegador el cual se puede pasar en el motor XSLT favorito o parseador.
Si no se esta interesado en formatear y solo se desea que la data sea cargada en la variable
tradicional $_POST, se puede instruir al navegador del cliente para enviarlos como application/xwww-form-urlencoded cambiando el atributo method a urlencoded-post.
Ejemplo #2 Usando un Xform para rellenar $_POST
<h:html xmlns:h="http://www.w3.org/1999/xhtml"
xmlns="http://www.w3.org/2002/xforms">
<h:head>
<h:title>Busqueda</h:title>
<model>
<submission action="http://example.com/search"
method="urlencoded-post" id="s"/>
</model>
</h:head>
<h:body>
<h:p>
<input ref="q"><label>Buscar</label></input>
<submit submission="s"><label>Ir</label></submit>
</h:p>
</h:body>
</h:html>
Manejando la carga de archivos
Carga con el método POST
Esta característica permite que los usuarios envien tanto archivos de texto como binarios. Con la
autenticación de PHP y las funciones de manipulación de archivos, se tiene completo control sobre
quién está autorizado a cargar y que hay que hacer con el archivo una vez que se ha cargado.
PHP es capaz de recibir cargas de archivos de cualquier navegador compatible con RFC-1867.
Nota: Configuraciones Relacionadas
Ver también las
directivas file_uploads, upload_max_filesize, upload_tmp_dir, post_max_size y max_input_time en p
hp.ini
PHP también soporta el método PUT para la carga como lo utilizan los clientes Netscape
Composer y Amaya del W3C. Ver el soporte del método PUT para más detalles.
Ejemplo #1 Formulario para la carga de archivos
Una página de carga de archivos puede ser construida mediante la creación de un formulario especial
el cual se vería algo como esto:
<!-- El tipo de codificación de datos, enctype, se DEBE especificar como a continuación -->
<form enctype="multipart/form-data" action="__URL__" method="POST">
<!-- MAX_FILE_SIZE debe preceder el campo de entrada de archivo -->
<input type="hidden" name="MAX_FILE_SIZE" value="30000" />
<!-- El nombre del elemento de entrada determina el nombre en el array $_FILES -->
Enviar este archivo: <input name="userfile" type="file" />
<input type="submit" value="Send File" />
</form>
El __URL__ en el ejemplo anterior se debe sustituir y apuntar a un archivo PHP.
El campo oculto MAX_FILE_SIZE (medido en bytes) debe preceder al campo de entrada de archivo
y su valor es el tamaño máximo de archivo aceptado por PHP. Este elemento del formulario se debe
usar siempre, ya que evita a los usuarios la molestia de esperar a que un gran archivo sea
transferido sólo para descubrir que era demasiado grande y falló la transferencia. Tener en cuenta:
engañar a esta configuración en el lado del navegador es muy fácil, así que nunca se debe confiar en
que archivos con un tamaño mayor serán bloqueados por esta característica. Es simplemente una
característica de conveniencia para los usuarios en el lado cliente de la aplicación. Sin embargo, la
configuración de PHP (en el lado del servidor) para un máximo de tamaño, no puede ser engañada.
Nota:
Asegúrese de que el formulario de subida de archivos tiene el atributo enctype="multipart/formdata" de lo contrario la carga de archivos no funcionará.
El $_FILES global existe a partir de PHP 4.1.0 (Usar $HTTP_POST_FILES en su lugar si se utiliza una
versión anterior). Este array contendrá toda la información sobre el archivo cargado.
El contenido de $_FILES del formulario de ejemplo es el siguiente. Tenga en cuenta que esto asume
la utilización del nombre del archivo cargado userfile, tal como se utiliza en el script de ejemplo
anterior. Este puede ser cualquier nombre.
$_FILES['userfile']['name']
El nombre original del archivo en la máquina cliente.
$_FILES['userfile']['type']
El tipo mime del archivo, si el navegador proporciona esta información. Un ejemplo podría
ser "image/gif". Este tipo mime, sin embargo no se verifica en el lado de PHP y por lo tanto
no se garantiza su valor.
$_FILES['userfile']['size']
El tamaño, en bytes, del archivo subido.
$_FILES['userfile']['tmp_name']
El nombre temporal del archivo en el cual se almacena el archivo cargado en el servidor.
$_FILES['userfile']['error']
El código de error asociado a esta carga de archivo. Este elemento fue añadido en PHP 4.2.0
Los archivos, por defecto se almacenan en el directorio temporal por defecto
del servidor, a menos que otro lugar haya sido dado con la
directivaupload_tmp_dir en php.ini. El directorio por defecto del servidor puede
ser cambiado mediante el establecimiento de la variable de entorno TMPDIR en
el entorno en el cual se ejecuta PHP. Configurarlo usando putenv() desde un
script PHP no funcionará. Esta variable de entorno también se puede utilizar
para asegurarse de que las demás operaciones están trabajando sobre los
archivos cargados.
Ejemplo #2 Validación de la carga de archivos
Ver también las entradas para las
funciones is_uploaded_file() y move_uploaded_file() para más información. El
siguiente ejemplo procesaría la carga de archivo que vendría de un formulario.
<?php
// En versiones de PHP anteriores a 4.1.0, $HTTP_POST_FILES debe utilizarse
en lugar
// de $_FILES.
$uploaddir = '/var/www/uploads/';
$uploadfile = $uploaddir . basename($_FILES['userfile']['name']);
echo '<pre>';
if (move_uploaded_file($_FILES['userfile']['tmp_name'], $uploadfile)) {
echo "El archivo es válido y fue cargado exitosamente.\n";
} else {
echo "¡Posible ataque de carga de archivos!\n";
}
echo 'Aquí hay más información de depurado:';
print_r($_FILES);
print "</pre>";
?>
El script PHP que recibe el archivo cargado, debe implementar cualquier lógica
que sea necesaria para determinar qué se debe hacer con el archivo subido. Se
puede, por ejemplo, utilizar la variable $_FILES['userfile']['size'] para
descartar cualquier archivo que sea demasiado pequeño o demasiado grande.
Se podría utilizar la variable $_FILES['userfile']['type'] para descartar cualquier
archivo que no corresponda con un cierto criterio de tipo, pero usando esto
sólo como la primera de una serie de verificaciones, debido a que este valor
está completamente bajo el control del cliente y no se comprueba en el lado de
PHP. A partir de PHP 4.2.0, se puede usar $_FILES['userfile']['error'] y el
planear la lógica de acuerdo con los códigos de error. Cualquiera que sea la
lógica, se debe borrar el archivo del directorio temporal o moverlo a otra parte.
Si ningún archivo es seleccionado para realizar la carga en el formulario, PHP
devolverá $_FILES['userfile']['size'] como 0,
y $_FILES['userfile']['tmp_name']como ninguno.
El archivo será borrado del directorio temporal al final de la solicitud si no se
ha movido o renombrado.
Ejemplo #3 Cargando un array de archivos
PHP soporta las funcionalidades array de HTML incluso con archivos.
<form action="" method="post" enctype="multipart/form-data">
<p>Pictures:
<input type="file" name="pictures[]" />
<input type="file" name="pictures[]" />
<input type="file" name="pictures[]" />
<input type="submit" value="Send" />
</p>
</form>
<?php
foreach ($_FILES["pictures"]["error"] as $key => $error) {
if ($error == UPLOAD_ERR_OK) {
$tmp_name = $_FILES["pictures"]["tmp_name"][$key];
$name = $_FILES["pictures"]["name"][$key];
move_uploaded_file($tmp_name, "data/$name");
}
}
?>
Una barra de progreso de carga de archivos puede ser implementada
mediante Session Upload Progress.
Explicación de los mensajes de error
A partir de PHP 4.2.0, PHP devuelve un código de error apropiado, junto con el array del archivo. El
código de error se puede encontrar en el segmento errordel array del archivo que PHP crea durante
la subida del archivo. En otras palabras, el error podría encontrarse en $_FILES['userfile']['error'].
UPLOAD_ERR_OK
Valor: 0; No hay error, archivo subido con éxito.
UPLOAD_ERR_INI_SIZE
Valor: 1; El archivo subido excede la directiva upload_max_filesize en php.ini.
UPLOAD_ERR_FORM_SIZE
Valor: 2; El archivo subido excede la directiva MAX_FILE_SIZE que fue especificada en el
formulario HTML.
UPLOAD_ERR_PARTIAL
Valor: 3; El archivo subido fue sólo parcialmente cargado.
UPLOAD_ERR_NO_FILE
Valor: 4; Ningún archivo fue subido.
UPLOAD_ERR_NO_TMP_DIR
Valor: 6; Falta la carpeta temporal. Introducido en PHP 4.3.10 y PHP 5.0.3.
UPLOAD_ERR_CANT_WRITE
Valor: 7; No se pudo escribir el archivo en el disco. Introducido en PHP 5.1.0.
UPLOAD_ERR_EXTENSION
Valor: 8; Una extensión de PHP detuvo la carga de archivos. PHP no proporciona una forma de
determinar cual extensión causó la parada de la subida de archivos; el examen de la lista de
extensiones cargadas con phpinfo() puede ayudar. Introducido en PHP 5.2.0.
Dificultades comunes
El item MAX_FILE_SIZE no puede especificar un tamaño de archivo mayor que el que ha sido
configurado en el upload_max_filesize en el archivo php.ini. Por defecto es 2 megabytes.
Si hay un límite de memoria activado, un memory_limit más grande puede ser necesario. Asegurarse
de configurar un memory_limit lo suficientemente grande.
Si el max_execution_time es demasiado pequeño, la ejecución del script puede excederse de este
valor. Asegurarse de configurar un max_execution_time lo suficientemente grande.
Nota: max_execution_time sólo afecta al plazo de ejecución del propio script. Todo el tiempo
gastado en actividades que tengan lugar por fuera de la ejecución del script, tales como las llamadas
al sistema usando system(), la función sleep(), las consultas a base de datos, el tiempo que tarda el
proceso de subida de archivos, etc., no se incluye cuando se determina el tiempo máximo que el
script ha estado funcionando.
Advertencia
max_input_time establece el tiempo máximo, en segundos, al script se le permite recibir información,
esto incluye la subida de archivos. Para archivos grandes o múltiples, o usuarios con conexiones más
lentas, el valor predeterminado de 60 segundos puede ser excedido.
Si post_max_size se establece demasiado pequeño, los archivos grandes no pueden ser cargados.
Asegurarse de configurar post_max_size lo suficientemente grande.
A partir de PHP 5.2.12, la configuración max_file_uploads controla el número máximo de archivos
que se pueden cargar en una petición. Si más archivos que ese límite son subidos,
entonces $_FILES parará de procesar archivos una vez se alcanza el límite. Por ejemplo,
si max_file_uploads se establece en 10, entonces $_FILES nunca contendrá más de 10 elementos.
No validar sobre cual archivo se opera puede significar que los usuarios pueden acceder a
información sensible en otros directorios.
Por favor tener en cuenta que el CERN httpd parece quitar todo lo que empieza con primer espacio en
blanco en la cabecera de tipo de contenido mime que recibe desde el cliente. Mientras este sea el
caso, el CERN httpd no soportará la funcionalidad de carga de archivos.
Debido a la gran cantidad de estilos de lista de directorios, no podemos garantizar que los archivos
con nombres exóticos (como el que contiene espacios en blanco) se manejen adecuadamente.
Un desarrollador no debe mezclar los campos input normales con los de carga de archivos en la
misma variable de formulario (mediante un nombre de inputcomo foo[]).
Subida de múltiples archivos
Múltiples archivos pueden ser subidos utilizando diferentes name para los input.
También es posible subir múltiples archivos simultáneamente y tener la información organizada
automáticamente en arrays. Para ello, es necesario utilizar la misma sintaxis de sumisión de array en
el formulario HTML como se hace con múltiples selects y checkboxes:
Ejemplo #1 Subida de múltiples archivos
<form action="file-upload.php" method="post" enctype="multipart/form-data">
Enviar estos archivos:<br />
<input name="userfile[]" type="file" /><br />
<input name="userfile[]" type="file" /><br />
<input type="submit" value="Send files" />
</form>
Cuando el formulario de arriba se remite, los
arrays $_FILES['userfile'], $_FILES['userfile']['name'] y $_FILES['userfile']['size'] serán inicializados
(así como en$HTTP_POST_FILES para las versiones de PHP anteriores a 4.1.0).
Cuando register_globals está activado, globales para los archivos subidos también se inicializan. Cada
uno de estos será un array indexado numéricamente de los valores correspondientes a los archivos
remitidos.
Por ejemplo, suponga que los nombres de archivo /home/test/review.html y /home/test/xwp.out son
remitidos. En este caso,$_FILES['userfile']['name'][0]contendría el valor review.html,
y $_FILES['userfile']['name'][1] contendría el valor xwp.out. De manera
similar, $_FILES['userfile']['size'][0] contendría el tamaño del archivo review.html y así
sucesivamente.
$_FILES['userfile']['name'][0], $_FILES['userfile']['tmp_name'][0], $_FILES['userfile']['size'][0],
y $_FILES['userfile']['type'][0] también son establecidos.
Advertencia
A partir de PHP 5.2.12, la configuración max_file_uploads actúa como un límite en el número de
archivos que se pueden subir en una petición. Se necesita asegurar que el formulario no intenta
cargar más archivos que este límite en una petición.
Soporte del método PUT
PHP ofrece soporte para el método HTTP PUT utilizado por algunos clientes para almacenar archivos
en un servidor. Las peticiones PUT son mucho más simples que una carga de archivos mediante
solicitudes POST y se ven algo como esto:
PUT /path/filename.html HTTP/1.1
Esto normalmente significa que el cliente remoto quiere guardar el contenido que sigue
como: /path/filename.html en el árbol web. Obviamente no es una buena idea para Apache o PHP
dejar automáticamente a todo el mundo que pueda sobrescribir cualquier archivo del árbol web. Para
manejar esta solicitud se debe primero decir al servidor web que se desea que cierto script de PHP
maneje la petición. En Apache se hace esto con la directiva de Script. Se puede colocar casi en
cualquier parte del archivo de configuración de Apache. Un lugar común es dentro de un
bloque <Directory> o tal vez dentro de un bloque<VirtualHost>. Una línea como ésta haría el
truco:
Script PUT /put.php
Esto le dice a Apache que envíe todas peticiones PUT para URIs que coincidan con el contexto en el
cual se pone esta línea en el script put.php. Esto asume, por supuesto, que se tiene habilitado PHP
para la extensión .php y que PHP está activo. El recurso de destino para todas las solicitudes PUT a
este script tiene que ser en propio script, el archivo subido no debe tener un nombre de archivo.
Con PHP entonces se haría algo como lo siguiente en el put.php. Esto copiaría el contenido del
archivo subido al archivo myputfile.ext en el servidor. Es probable que se deseen realizar algunas
verificaciones y/o autenticar al usuario antes de realizar esta copia de archivo.
Ejemplo #1 Guardando archivos HTTP PUT
<?php
/* datos PUT vienen en en el flujo de entrada estándar
$putdata = fopen("php://input", "r");
*/
/* Abre un archivo para escribir */
$fp = fopen("myputfile.ext", "w");
/* Leer los datos de 1 KB a la vez
y escribir en el archivo */
while ($data = fread($putdata, 1024))
fwrite($fp, $data);
/* Cerrar los flujos */
fclose($fp);
fclose($putdata);
?>
Usando archivos remotos
Siempre que allow_url_fopen este habilitado en php.ini, se pueden usar URLs HTTP y FTP con la
mayoría de las funciones que toman un nombre de archivo como parámetro. Además, las URLs
pueden ser usadas con las declaraciones include, include_once, require y require_once (desde PHP
5.2.0,allow_url_include debe ser habilitado para esto). Ver Protocolos y Envolturas
soportados para más información de los protocolos soportados por PHP.
Nota:
En PHP 4.0.3 y anteriores, con el fin de usar capas de URL, se requirió de configurar PHP usando la
opción de configuración --enable-url-fopen-wrapper .
Nota:
Las versiones Windows de PHP más nuevas a la PHP 4.3 no soportan acceso remoto a los archivos
por las siguientes funciones: include, include_once,require, require_once, y las funciones
imagecreatefromXXX en la extensión Funciones de GD e Imágenes
Por ejemplo, se puede usar esto para abrir un archivo en un web server remoto, analizar la salida de
los datos que se quieren, y entonces usar esos datos en una consulta a la base de datos, o
simplemente para mostrarlos en un estilo que coincida con el resto del sitio web.
Ejemplo #1 Obteniendo el titulo de una página remota
<?php
$file = fopen ("http://www.example.com/", "r");
if (!$file) {
echo "<p>Imposible abrir el archivo remoto.\n";
exit;
}
while (!feof ($file)) {
$line = fgets ($file, 1024);
/* Esto solo trabaja si el titulo y sus tags estan en una línea */
if (preg_match ("@\<title\>(.*)\</title\>@i", $line, $out)) {
$title = $out[1];
break;
}
}
fclose($file);
?>
También se pueden escribir archivos en un servidor FTP (considerando que se esta conectado como
un usuario con los permisos de acceso correctos). Se pueden crear únicamente archivos nuevos
usando este método. Si se intenta sobreescribir un archivo que ya existe, la llamada a la
función fopen() fallará.
Para conectarse como un usuario diferente a 'anonymous', se necesita especificar el usuario (y
posiblemente el password) con la URL, tal como
'ftp://user:[email protected]/path/to/file'. (Se puede usar la misma sintaxis para
accesar archivos vía HTTP cuando se requiere autenticación básica).
Ejemplo #2 Almacenando datos en un servidor remoto
<?php
$file = fopen ("ftp://ftp.example.com/incoming/outputfile", "w");
if (!$file) {
echo "<p>Imposible abrir el archivo remoto para escritura.\n";
exit;
}
/* Escribir los datos aqui. */
fwrite ($file, $_SERVER['HTTP_USER_AGENT'] . "\n");
fclose ($file);
?>
Manejo de Conexiones
Internamente en PHP se mantiene un estatus de la conexión. Hay 3 posibles estados:



0 - NORMAL
1 - ABORTED
2 - TIMEOUT
Cuando un script en PHP esta ejecutándose, normalmente esta activo el estado NORMAL. Si el cliente
remoto se desconecta, el flag ABORTED es activado. Un cliente remoto se desconecta usualmente
porque el usuario presiona su botón STOP. Si el tiempo limite PHP-imposed (ver set_time_limit()) es
activado, el flag TIMEOUT se activa.
Se puede decidir si se desea que un cliente se desconecte o no a causa de que se aborte el script.
Algunas veces es útil que los scripts se ejecuten inclusive si ya no hay un navegador recibiendo la
salida. El comportamiento por defecto es que el script sea abortado cuando el cliente remoto se
desconecte. Este comportamiento puede ser establecido a través de la directiva ignore_user_abort
en php.ini así como a través de la directiva correspondiente de Apache enhttpd.conf php_value
ignore_user_abort o con la función ignore_user_abort(). Si se decide no decirle a PHP que ignore
abortar al usuario y el usuario aborta, el script terminará. La única excepción es si se tiene registrada
una función de cierre usando register_shutdown_function(). Con una función de cierre, cuando el
usuario remoto activa el botón STOP, la próxima vez que el script intente mostrar algo, PHP detectará
que la conexión fue abortada y la función de cierre es llamada. Esta función de cierre también es
llamada al final del script cuando termina normalmente, así que para hacer algo diferente en el caso
de que un cliente se desconecte usar la función connection_aborted(). Esta función retornará TRUE si
la conexión fue abortada.
El script puede ser terminado también por el temporizador incorporado en los scripts. El tiempo por
defecto es de 30 segundos. Puede ser cambiado usando la
directiva max_execution_time de php.ini o la correspondiente directiva php_value
max_execution_time de Apache httpd.conf así como con la funciónset_time_limit(). Cuando el
temporizador expira el script será abortado y así como el caso del cliente anterior que se desconecto,
si la función de cierre ha sido registrada ésta será llamada. Dentro de esta función de cierre se puede
comprobar para ver si el timeout causa la función de cierre llamando a la funciónconnection_status().
Esta función retornará 2 si el timeout causo la llamada a la función de cierre.
Una cosa a notar es que ambos estados ABORTED y TIMEOUT pueden ser activados al mismo tiempo.
Esto es posible si se le dice a PHP que ignore el aborto del usuario. PHP notará de hecho que un
usuario podría haber roto la conexión, pero el script se mantendrá ejecutándose. Si este activa el
limite de tiempo será abortado y la función de cierre, si existe, será llamada. A este punto, se
encontrará que connection_status() retorna 3.
Conexiones Persistentes a Bases de Datos
Las conexiones persistentes son enlaces que no se cierran cuando la ejecución del script termina.
Cuando una conexión persistente es solicitada, PHP chequea si ya existe una conexión persistente
idéntica (que fuera abierta antes) - y si existe, la usa. Si no existe, crea el enlace. Una conexión
"Idéntica" es una conexión que fue abierta por el mismo host, con el mismo usuario y el mismo
password (donde sea aplicable).
Las personas que no estan completamente familiarizadas con como trabajan los web servers y la
distribución de carga podrían equivocarse en usar conexiones persistentes para lo que no son. En
particular, no le da la habilidad de abrir "sesiones de usuario" en el mismo enlace, no le da la
habilidad de construir una transacción eficiente, pero no hacen muchas otras cosas más. De hecho,
para ser extremadamente claros acerca de esto, las conexiones persistentes no dancualquier otra
funcionalidad que no fuera posible hacerse con sus hermanas no-persistentes.
¿Por qué?
Esto tiene que ver con la forma en que los web servers trabajan. Hay 3 formas en las cuales el web
server puede generar paginas web usando PHP.
El primer método es usar PHP como una "capa" CGI. Cuando se ejecuta de esta forma, una instancia
del interprete PHP es creado y destruido por cada solicitud de la página (para una página PHP) al web
server. Porque es destruido después de cada solicitud, cualquier recurso que se necesite (como un
enlace a un servidor de base de datos SQL) son cerradas cuando son destruidas. En este caso, no se
gana nada intentando usar conexiones persistentes -- simplemente no persisten.
La segunda, y mas popular, es ejecutar PHP como un modulo en un servidor multiproceso, el cual
actualmente solo incluye a Apache. Un servidor multiproceso normalmente tiene un proceso (el
padre) el cual coordina un grupo de procesos (los hijos) los cuales no trabajan sirviendo páginas web.
Cuando una solicitud viene desde el cliente, es manejada por uno de los hijos el cual no este
sirviendo a otro cliente. Esto significa que cuando el mismo cliente hace una segunda solicitud al
servidor, podría ser servido por un proceso hijo diferente a la primera vez. Cuando se abre una
conexión persistente, cada petición siguiente de servicios SQL puede reusar la misma conexión
establecida al servidor SQL.
El último método es usar PHP como un plug-in para un servidor web multihilos. Actualmente PHP 4
tiene soporte para ISAPI, WSAPI, y NSAPI (en Windows), los cuales permiten usar PHP como un
plug-in multihilo en servidores como Nestcape FastTrack (iPlanet), Microsoft Internet Information
Server (IIS), y O'Reilly's WebSite Pro. El comportamiento es esencialmente el mismo para el modelo
multiproceso descrito antes.
Si las conexiones persistentes no tienen ninguna funcionalidad adicional, ¿Para que son buenas?
La respuesta es extremadamente simple -- eficiencia. Las conexiones persistentes son buenas si la
sobrecarga para crear enlaces al servidor SQL son altas. Que hallan o no sobrecargas depende de
muchos factores. Como, cual base de datos se usa, que sea o no la misma computadora en que esta
el servidor web, así como la carga de la maquina que tiene el servidor SQL y así por el estilo. Lo
esencial es que si la sobrecarga de conexiones es alta, las conexiones persistentes ayudan
considerablemente. Podrían causar que los procesos hijos únicamente se conecten una vez en todo lo
que duran, en lugar de que se haga cada vez que se procese una página que se conecte a un servidor
SQL. Esto significa que por cada hijo que abrió una conexión persistente mantendrá una conexión
persistente al servidor. Por ejemplo, si se tienen 20 procesos hijos diferentes que ejecutaran un script
que hace una conexión persistente al servidor SQL, se tendrían 20 conexiones diferentes al servidor
SQL, una por cada hijo.
Nótese, sin embargo, que esto puede tener algunos inconvenientes si se esta usando una base de
datos con un limite de conexiones que sean excedidas por las conexiones persistentes hijas. Si la
base de datos tiene un limite de 16 conexiones simultaneas, y en el curso de una sesión ocupada del
servidor, 17 hilos intentan conectarse, uno no sera posible de hacerse. Si hay bugs en los scripts los
cuales no contemplen los cierres de las conexiones (como un loop infinito), la base de datos con los
16 conexiones podría rápidamente hundida. Chequear la documentación de la base de datos para
obtener información de como manejar conexiones abandonadas u ociosas.
Advertencia
Hay un par de advertencias mas que tener en mente cuando se usan conexiones persistentes. Una es
que cuando se usan bloqueos de tablas con una conexión persistente, si el script por alguna razón no
puede soltar el bloqueo, entonces los scripts subsecuentes que usan la misma conexión serán
bloqueadas indefinidamente y podría ser necesario reiniciar el servidor httpd o el servidor de la base
de datos. Otra cosa es que cuando se usan transacciones, una transacción bloqueada también podría
llevar al siguiente script el cual usa la conexión si la ejecución del script termina antes que el bloqueo
lo haga. En ese caso, se puede usar register_shutdown_function() para registrar una función de
limpieza para desbloquear las tablas o deshacer la transacción. Mejor aún es evitar este problema por
completo no usando conexiones persistentes en scripts los cuales usan bloqueo de tablas o
transacciones (se pueden usar en otros lugares).
Un resumen importante. Las conexiones persistentes fueron diseñadas para tener conexiones
normales uno a uno. Esto significa siempre que se podría ser capaz de reemplazar conexiones
persistentes con conexiones no-persistentes, y no cambiaría la forma en que este se comporte.
Esto podría (y probablemente lo hará) cambiar la eficiencia del script, pero no su comportamiento!.
Ver
también fbsql_pconnect(), ibase_pconnect(), ifx_pconnect(), ingres_pconnect(), msql_pconnect(), m
ssql_pconnect(), mysql_pconnect(), ociplogon(),odbc_pconnect(), oci_pconnect(), pfsockopen(), pg_
pconnect(), and sybase_pconnect().
Descargar