La gestión de los archivos subidos con PHP, al igual que en otros lenguajes de programación orientados a la web, implica el uso de código HTML y de programación en el servidor. En esta sección se muestran las herramientas ofrecidas por el framework para simplificar el trabajo del programador y también se muestra cómo evitar los errores habituales.
A continuación se modifica el formulario de contacto para permitir adjuntar archivos al mensaje. Para ello, se añade un campo llamado archivo
, tal y como muestra el listado 2-17.
Listado 2-17 - Añadiendo un campo archivo
en el formulario ContactoForm
// lib/form/ContactoForm.class.php
class ContactoForm extends sfForm
{
protected static $asuntos = array('Asunto A', 'Asunto B', 'Asunto C');
public function configure()
{
$this->setWidgets(array(
'nombre' => new sfWidgetFormInput(),
'email' => new sfWidgetFormInput(),
'asunto' => new sfWidgetFormSelect(array('choices' => self::$asuntos)),
'mensaje' => new sfWidgetFormTextarea(),
'archivo' => new sfWidgetFormInputFile(),
));
$this->widgetSchema->setNameFormat('contacto[%s]');
$this->setValidators(array(
'nombre' => new sfValidatorString(array('required' => false)),
'email' => new sfValidatorEmail(),
'asunto' => new sfValidatorChoice(array('choices' => array_keys(self::$asuntos))),
'mensaje' => new sfValidatorString(array('min_length' => 4)),
'archivo' => new sfValidatorFile(),
));
}
}
Cuando se utiliza un widget de tipo sfWidgetFormInputFile
para permitir la subida de archivos, se debe añadir el atributo enctype
en la etiqueta <form>
, tal y como se muestra en el listado 2-18.
Listado 2-18 - Modificando la plantilla para tener en cuenta el campo archivo
<form action="<?php echo url_for('contacto/index') ?>" method="POST" enctype="multipart/form-data">
<table>
<?php echo $formulario ?>
<tr>
<td colspan="2">
<input type="submit" />
</td>
</tr>
</table>
</form>
Nota Si generas de forma dinámica las plantillas asociadas a los formularios, puedes emplear el método isMultipart()
del objeto del formulario, ya que devuelve true
si el formulario requiere el atributo enctype
.
La información de los archivos subidos no se almacena junto con el resto de información enviada. Por eso, es necesario modificar la llamada al método bind()
para pasar esa información como segundo parámetro, tal y como se muestra en el listado 2-19.
Listado 2-19 - Pasando los archivos subidos al método bind()
class contactoActions extends sfActions
{
public function executeIndex($request)
{
$this->formulario = new ContactoForm();
if ($request->isMethod('post'))
{
$this->formulario->bind($request->getParameter('contacto'), $request->getFiles('contacto'));
if ($this->formulario->isValid())
{
$valores = $this->formulario->getValues();
// hacer cosas con los valores
// ...
}
}
}
public function executeGracias()
{
}
}
Aunque el formulario ya es completamente funcional, es necesario modificar la acción para almacenar el archivo subido en un directorio. Como se explica al principio de este capítulo, el validador sfValidatorFile
convierte toda la información relacionada con el archivo subido en un objeto de tipo sfValidatedFile
. El listado 2-20 muestra cómo utilizar este objeto para almacenar el archivo subido en el directorio web/uploads
.
Listado 2-20 - Utilizando el objeto sfValidatedFile
if ($this->formulario->isValid())
{
$archivo = $this->formulario->getValue('archivo');
$nombreArchivo = 'subido_'.sha1($archivo->getOriginalName());
$extension = $archivo->getExtension($archivo->getOriginalExtension());
$archivo->save(sfConfig::get('sf_upload_dir').'/'.$nombreArchivo.$extension);
// ...
}
La siguiente tabla muestra todos los métodos del objeto sfValidatedFile
:
Método | Descripción |
---|---|
save() |
Guarda el archivo subido |
isSaved() |
Devuelve true si el archivo se ha guardado |
getSavedName() |
Devuelve el nombre del archivo guardado |
getExtension() |
Devuelve la extensión del archivo, en función de su tipo MIME |
getOriginalName() |
Devuelve el nombre del archivo subido |
getOriginalExtension() |
Devuelve la extensión del nombre del archivo subido |
getTempName() |
Devuelve la ruta del archivo temporal |
getType() |
Devuelve el tipo MIME del archivo |
getSize() |
Devuelve el tamaño del archivo |
Nota El tipo MIME que proporciona el navegador por cada archivo subido no es fiable. Para asegurar la máxima seguridad, durante la validación del archivo se ejecutan de forma secuencial las funciones finfo_open
y mime_content_type
y la herramienta file
. Si ninguna de esas funciones es capaz de determinar el tipo MIME del archivo y si el sistema tampoco es capaz de proporcionarlo, se utiliza como último recurso el tipo MIME ofrecido por el navegador. Para añadir o modificar las funciones que tratan de averiguar el tipo MIME, se utiliza la opción mime_type_guessers
en el constructor de sfValidatorFile
.