(tratto dal sito: http://www.mmkit.com)

PHP MySQL - Trasferire files con le funzioni FTP - Download: This is a Zip file

Tempo fa realizzai un (mini)programma per un progetto didattico inerente le funzioni ftp.
Successivamente lo rimaneggiai e lo riadattai ad un contesto di tipo lavorativo aggiungendovi delle funzioni di gestione 'multiutenza' e 'superutenza'.
Con questo articolo ho deciso di pubblicare il codice e di renderlo disponibile a chiunque ne avesse necessità.


Il programma è autoconfigurante e ciò comporta che per creare il DB col quale esso si relaziona, è sufficente richiamare il file "configurazione.php" e seguire la procedura guidata (ho cercato di renderla il più possibile user-friendly :-) ).
Lo script di configurazione interroga il server MySQL per verificare l'esistenza del DB e in caso di risposta negativa ne creerà uno nominandolo come deciso dall'utente.
Simultaneamente verrà scritto un file (conf.php) contenente le variabili che saranno poi utilizzate per la connessione ftp (se già esistente verrà sovrascritto).
L'ultimo step prevede la creazione della tabella necessaria e la creazione dell'account "superuser".

Fatto questo se tutto sarà andato a buon fine, si passerà alla pagina index.php contente l'area di checklogin e il link al pannello/modulo di registrazione dei singoli utenti.

Nota: (Il trasferimento dei files è possibile farlo solo se loggati come utenti normali e non come superutente. Il Superutente può solamente accedere alle cartelle dei singoli utenti ed eseguire il download o l'eliminazione dei rispettivi files.)

Tra le altre cose il software comprende uno script che visualizza il contenuto delle singole cartelle in una pagina web con i links per il download e la cancellazione-eliminazione dello stesso file.

Premessa:
Il codice è modificabile in ogni sua parte e, poichè si tratta comunque di una versione DEMO che ha il puro e semplice scopo di fornire un valido esempio a coloro che devono creare piccole applicazioni ftp, potrebbe presentare alcuni bugs. Ho utilizzato anche un metodo poco ortodosso per la rinominazione di cartelle e files. (Lascio a voi lo studio di una soluzione alternativa ;-) ).
 

PHP MySQL - Upload Immagini - Download: This is a Zip file

Con questo articolo invece vediamo come utilizzare il PHP per effettuare l'upload, modificare e cancellare immagini da un database MySQL. L'esempio tratta immagini ed swf, ma è facilmente adattabile a qualsiasi tipo di file.


Parte del codice che ho utilizzato per scrivere questo tutorial è tratto dall'articolo "File uploads made easy" di Darren Beale, ma in buona parte è stato modificato per interfacciarlo ad un database.

L'esempio, che potete scaricare cliccando sul tasto per il download, è formato da 2 files php:
- upload.php
- getdata.php

Il file principale è il primo, dato che contiene tutto il codice per la gestione delle immagini.
Da premettere che i file sono perfettamente funzionanti (a condizione di una giusta configurazione dei parametri di connessione al db), ma per comprendere appieno il codice occorre avere già una infarinata di PHP, dato che non mi soffermerò troppo sul significato dei comandi utilizzati.
La prima cosa da fare è definire una serie di variabili globali (come l'esempio di Beale):

$my_max_file_size = "307200"; //sarebbero 300Kb
$image_max_width = "400"; // in pixel
$image_max_height = "500"; // in pixel

$registered_types = array(
  "application/x-gzip-compressed" => ".tar.gz, .tgz",
  "application/x-zip-compressed" => ".zip",
  "application/x-tar" => ".tar",
  "text/plain" => ".html, .php, .txt, .inc",
  "image/bmp" => ".bmp, .ico",
  "image/gif" => ".gif",
  "image/pjpeg" => ".jpg, .jpeg",
  "image/jpeg" => ".jpg, .jpeg",
  "application/x-shockwave-flash" => ".swf",
  "application/msword" => ".doc",
  "application/vnd.ms-excel" => ".xls",
  "application/octet-stream" => ".exe, .fla" );


Di tutte queste ne utilizziamo solo le seguenti:

$allowed_types = array("image/gif","image/pjpeg","image/jpeg","application/x-shockwave-flash");


Seguono poi tutte una serie di funzioni che verranno utilizzate a seconda delle operazioni da svolgere.
In realtà la prima istruzione che viene eseguita si trova alla riga 201:

dbconnect();

Richiama la funzione relativa alla connessione al database MySQL:

function dbconnect() {
  mysql_connect("db_host", "db_username", "db_password");
  @mysql_select_db("db_name") or die ("Unable to select database");
}


Sono le uniche righe da configurare per il corretto funzionamento del programma.
 

Nel database, creiamo una tabella che chiameremo mmkit_images con i seguenti campi:

id int(11) NOT NULL auto_increment,
bin_data longblob,
filename varchar(255),
filesize varchar(50),
filetype varchar(50),
filewidth varchar(50),
fileheight varchar(50),
PRIMARY KEY (id)


che contengono rispettivamente i dati binari del file, il nome, la dimensione in byte, il tipo di file (jpg, gif, swf), la larghezza e l'altezza.
Nell'allegato è presente un file SQL, che se eseguito (ad esempio con phpMyAdmin) crea in automatico la tabella ed i relativi campi.
Ritornando al file upload.php, segue uno switch per richiamare la funzione desiderata:

switch($task) {
  case 'upload':
  upload($thefile);
  break;

  case 'delete':
  delete($id);
  break;

  case 'mod':
  mod($id);
  break;

  case 'change':
  change($thefile, $id);
  break;

  default:
  form($error);
}

Appena partiamo la funzione richiamata è form(), dove è presente la form per l'invio delle immagini. Il codice HTML è il seguente:

<form ENCTYPE="multipart/form-data" action="upload.php" method="post">
<INPUT TYPE="hidden" name="MAX_FILE_SIZE" value="307200">
<INPUT TYPE="hidden" name="task" value="upload">
<br><b>File</b>: <INPUT NAME="thefile" TYPE="file" SIZE="35"><br>
<br><input type="submit" Value="Invia">
</form>


La prima cosa da notare è che per poter inviare file al server è necessaria una form con il parametro ENCTYPE="multipart/form-data".
É importante anche il campo <INPUT TYPE="hidden" name="MAX_FILE_SIZE" value="xxx"> che definisce la dimensione massima del file da inviare. Da notare che comunque non sempre basta questo parametro per evitare l'upload di file giganteschi (infatti controlleremo sempre il file che arriva al server prima di inserirlo nel db), ma è una riga necessaria per il corretto funzionamento dell'upload.
Fate poi attenzione a non alzare troppo questo valore: in genere un database MySQL di default può accettare dati per un massimo di 2Mb per ogni campo LONGBLOB, ma può essere settato anche a meno. Quindi per conoscere qual è la dimensione massima dei file che potete inserire nel db dovete contattare l'amministratore del server che vi fornisce il servizio. In genere si può arrivare senza problemi a gestire file di 8Mb, ma sinceramente non ho mai provato.
La form punta sempre al file upload.php, ma come campo hidden abbiamo la variabile task=upload, che tramite lo switch visto poc'anzi richiamerà la funzione upload().
Una cosa molto interessante è che con questo tipo di form, il file inviato lo ritroviamo nella variabile $thefile, ma con esso ritroviamo in automatico anche le seguenti variabili (tutte global): $thefile_name, $thefile_size, che contengono il nome del file e la sua dimensione (in byte).
Per sapere invece le dimensioni in pixel dell'immagine basta eseguire:

$size = GetImageSize($thefile);

questa funzione restituisce (in una serie di valori contenuti in un array) le dimensione di immagini GIF, JPG, PNG, SWF, SWC, PSD, TIFF, BMP e IFF.
Per maggiori info php.net.
Preleviamo le variabili che ci interessano con un list:

list($foo,$width,$bar,$height) = explode(""",$size[3]);

così da avere in $width e $height la larghezza e l'altezza del file. Delle altre variabili possiamo farne a meno

Detto questo possiamo capire il funzionamento della funzione upload():
per prima cosa viene eseguito un test tramite la funzione validate_upload() per controllare se la dimensione in byte o in pixel dell'immagine sia contenuta nei limiti che abbiamo prefissato. Per i file swf (data la loro natura vettoriale), invece ho inserito un ridimensionamento automatico se le dimensioni risultano maggiori di quelle stabilite.
Le nuove variabili globali $g_height e $g_width vengono quindi settate alle dimensioni da inserire nel database.
Se l'immagine è accettata viene letta ed inserita nel db tramite questo codice:

$fp=@fopen($thefile, "r");
if ($fp){
  $data = addslashes(fread($fp, filesize($thefile)));
  $result=MYSQL_QUERY("UPDATE mmkit_images SET bin_data='$data',
  filename='$thefile_name', filesize='$thefile_size',   filetype='$thefile_type', filewidth='$g_width',
  fileheight='$g_height' WHERE id=$id");
  fclose($fp);
  if (!$result) { echo mysql_errno(). ": ".mysql_error(). " "; exit();}
  else Header("Location: upload.php");
} else { ...errore... }


Viene letto il file con il comando fopen (il @ prima di esso fa in modo di non stampare un messaggio di errore in caso di problemi... solamente per una sorta di pulizia del risultato dato che tutti i messaggi di errore sono inseriti con un echo), e dopo aver spostato il contenuto nella variabile $data viene inserito nel database con una query.
Se tutto è andato bene si viene reindirizzati su upload.php, altrimenti viene stampato un errore.
Per visualizzare le immagini invece c'è la funzione list_files():

function list_files() {
 $result=mysql_query("select id, filename, filetype, filewidth, fileheight from mmkit_images");
 if (mysql_num_rows($result) > 0) {
   echo"<table width="98%" border="1" cellspacing="1"cellpadding="1" bordercolor="#000000">
   <tr bgcolor="#999999"><td>Files presenti nel database:</td></tr>";
   while(list($id, $filename, $filetype, $width, $height)=mysql_fetch_row($result)) {
      echo"<tr bgcolor="#cccccc"><td><a href="upload.php?task=delete&id=$id">Delete</a>
      - <a href="upload.php?task=mod&id=$id">Modify</a></td></tr>";
      if (ereg("flash", $filetype)) {
        echo"<tr bgcolor="#FFFFFF"><td><object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
       codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=5,0,0,0"
        width="$width" height="$height"><param name=movie value="getdata.php?id=$id">
        <param name=quality value=high><embed src="getdata.php?id=$id" quality=high
        pluginspage="http://www.macromedia.com/shockwave/download/index.cgi?P1_Prod_Version=ShockwaveFlash"
        type="application/x-shockwave-flash" width="$width" height="$height">
        </embed></object></td></tr>";
      } else {
        echo"<tr bgcolor="#FFFFFF"><td><img src="getdata.php?id=$id"
        width="$width" height="$height"></td>
        </tr>";
      }
   }
   echo"</table>";
 } else echo"<br>Il database &egrave vuoto.";
}


Vengono presi tutti i record presenti nella tabella e viene stampato un codice HTML diverso a seconda se il file che dobbiamo visualizzare è di tipo immagine o di tipo Flash. Notiamo che nei relativi attributi src è inserito il file getdata.php?id=$id. Questo file è quello delegato a prendere i dati binari e a creare un header adatto.
 

Il codice del file getdata.php è tutto qui:

function dbconnect() {
  mysql_connect("db_host", "db_username", "db_password");
  @mysql_select_db("db_name") or die ("Unable to select database");
}

dbconnect();


if($id) {
  $query = "select bin_data, filetype FROM mmkit_images WHERE id='$id'";
  $result = @MYSQL_QUERY($query);
  $data = @MYSQL_RESULT($result,0,"bin_data");
  $type = @MYSQL_RESULT($result,0,"filetype");
  Header("Content-type: $type");
  echo $data;
};


Infatti dopo la connessione al database, viene prelevata l'immagine ed il relativo filetype e viene inviato un nuovo content-type relativo al tag html che si sta eseguendo ed il suo contenuto.
Una volta che eseguite i files in allegato troverete anche la possibilità di eliminare o di cambiare un'immagine. Il codice è piuttosto semplice (si tratta solamente di eseguire delle query):

$result=MYSQL_QUERY("UPDATE mmkit_images SET bin_data='$data', filename='$thefile_name', filesize='$thefile_size', filetype='$thefile_type', filewidth='$g_width', fileheight='$g_height' WHERE id=$id");

per l'aggiornamento di un'immagine e

mysql_query("delete from mmkit_images WHERE id=$id");

per la sua cancellazione.

Vi ricordo che per un corretto funzionamento dei files in allegato, il server che userete deve supportare il PHP, dovete avere accesso ad un database MySQL su cui dovete aver creato la tabella con le caratteristiche presenti nel file mmkit_images.sql (basta eseguirlo con phpMyAdmin oppure con una query in php) e dovete configurare i parametri di connessione al db nei file upload.php (righe 28-29) e getdata.php (righe 3-4).
Inoltre i file upload.php e getdata.php si devono trovare nella stessa directory.
Il codice inoltre si presta alla possibilità di usare e gestire anche altri tipi di file (.zip ad esempio): basta fare poche modifiche ed eliminare la parte relativa alle dimensionamento in pixel del file.

Aggiornamento 20 settembre 2004

La sintassi usata nell'esempio considera la variabile register_globals su on.
Dato che la sintassi è già indicata come deprecated, conviene usare le variabili super global per la gestione delle variabili provenienti da una form.
Quindi le vairabili provenienti dalla form per la selezione del file vanno presi e gestiti con $_REQUEST o $_POST (ad esmepio $_POST['task'], invece di $task), mentre il file viene gestito con la variabile $_FILES:
$thefile_name diventa $_FILES['thefile']['name']
$thefile_size diventa $_FILES['thefile']['size']
$thefile_type diventa $_FILES['thefile']['type']

Per maggiori info sulla variabile $_FILES clicca qui

PHP MySQL - Invio mail con allegati - Download: This is a Zip file

Alcuni giorni fa, per finire un lavoro, ho dovuto preparare una form per l'invio di un curriculum da mandare, insieme ai dati richiesti, ad un determinato indirizzo mail. Non avevo mai affrontato il problema degli attach, ma sapevo che la cosa non era difficile, dato che esiste una vasta documentazione in merito... Ovviamente mi sbagliavo: ho perso una mattinata intera. Così ho deciso di scrivere questo tutorial sperando di far risparmiare tempo a chi ha lo stesso problema. In allegato inoltre è disponibile un file php perfettamente funzionante (c'è da cambiare solo l'indirizzo e-mail del destinatario).


Questo esempio tratta l'invio di una serie di dati (nome, cognome, email, ecc...) insieme ad un curriculum in formato .doc.
Per prima cosa quindi prepariamo la form che deve essere del tipo:

<form enctype="multipart/form-data" method="post" action="nome_pagina.php" name="contatti">

ed oltre ai campi testuali, inseriamo anche la parte per la selezione del file .doc:

<input type="hidden" name="MAX_FILE_SIZE" value="102400">
<input name="thefile" type="file" SIZE="35">


Il campo hidden MAX_FILE_SIZE è obbligatorio per il corretto funzionamento del tutto, ed esprime la dimensione massima del file da inviare (in questo caso 100Kb). Nota che comunque viene fatto un ulteriore controllo prima di spedire la mail.
Una volta inviati i dati, vengono fatti i dovuti controlli sui campi obbligatori e sul file inviato (vengono accettati solo i files .doc).
Se tutto va bene viene preparata la mail.
Per inviare una mail con attach è necessario agire sugli header per impostare un messaggio in più parti: una parte che contiene il testo della mail ed un'altra che contiene i dati del file allegato.
L'header è del tipo:

MIME-Version: 1.0
Content-Type: multipart/mixed; boundary="XX-1234DED00099A"
Content-Transfer-Encoding: 7bit
From: $email

ed il messaggio del tipo:

--XX-1234DED00099A

---Testo del messaggio---

--XX-1234DED00099A
Content-Type: application/octet-stream; name="curriculum.doc"
Content-Transfer-Encoding: base64
Content-Description: "Curriculum"
Content-Disposition: attachment

---Curriculum in codifica base64---


--XX-1234DED00099A--
Il comando php per inviare una mail è il seguente:

mail("Email del destinatario", "Oggetto della mail", "Messaggio", "Headers")

Quindi l'header diventa:

$headers = "MIME-Version: 1.0\n";
$headers .= "Content-Type: multipart/mixed; boundary=\"XX-1234DED00099A\"\n";
$headers .= "Content-Transfer-Encoding: 7bit\n";
$headers .= "From: $email\n";


Ed il messaggio:

$messaggio="--XX-1234DED00099A\n";
$messaggio.="Content-Type: text/plain; charset=iso-8859-1\n";
$messaggio.="Content-Transfer-Encoding: 7bit\n\r";
$messaggio.="Testo della mail"
$messaggio.="--XX-1234DED00099A\n";
$messaggio.="Content-Type: application/octet-stream; name=\"curriculum.doc\"\n";
$messaggio.="Content-Transfer-Encoding: base64\n";
$messaggio.="Content-Description: \"Curriculum\"\n";
$messaggio.="Content-Disposition: attachment\n\r";
$fp=@fopen($thefile, "r");
if ($fp) { $data = fread($fp, filesize($thefile)); }
$curr = base64_encode($data);

$messaggio .= "$curr";


Ed il gioco è fatto.
La parte in blu è relativa alla trasformazione del file in codifica base64.

Note

Una delle cose che mi ha causato più problemi è stato il fatto che nei vari siti di riferimento per la documentazione delle mail multipart, le intestazioni delle varie parti del messaggio hanno come caratteri per andare a capo \n\r.
Il doppio uso di \r e \n dipende dal fatto che il carattere di "nuova linea" non è standard per tutte le piattaforme ed inserendole tutte e due si coprono tutte le possibilità.
Purtroppo usando \n\r, tutte le mail che mi arrivavano non venivano visualizzate nel modo giusto, perchè il carattere \r non veniva riconosciuto.
Inserendo\r solo nei messaggi, il problema è stato risolto; quindi se vi capita un problema analogo su altre piattaforme, dovrebbe essere il caso di sostituire tutti gli \n con \n\r.

Il file in allegato, inoltre, comprende anche l'invio automatico di una conferma all'indirizzo email dell'utente.
Per il corretto funzionamento del file è necessario inserire l'indirizzo mail del destinatario alla riga 73 del file allegato a questo articolo (all'interno della variabile $emailto).
Se volete modificare la dimensione massima del curriculum da inviare dovete modificare il campo hidden nella form (riga 160) e la variabile $my_max_file_size (riga 10).
Ovviamente è possibile modificare il codice per accettare altri tipi di file e non solo i .doc. ;-)

Buon divertimento.