Naeh.net Le mémo du développeur

7août/110

upload avec barre de progression

dans cet article-tuto nous allons voir comment mettre en place un système d'upload avec une sympathique barre de progression.

les pré-requis :
- un serveur web Apache
- PHP5 avec l'extension APC
- jquery

dans ce tuto je pars du principe qu'Apache et PHP sont installés et fonctionnels, on va juste voir comment installer APC et activer le suivi de la progression d'upload :

apt-get install php-apc
vim /etc/php5/apache2/conf.d/apc.ini

ajouter à la fin du fichier :

apc.rfc1867 = on

cette ligne magique, activera la suivi de progression d'upload sur le serveur.

on reload apache :

/etc/init.d/apache2 reload

le coté système de la chose est maintenant terminé, passons à l'upload :

pour la petite histoire, voici ce que l'on va faire :
on va créer un formulaire, qui sera validé vers (target) une iframe invisible, le temps que l'upload se passe, on va contacter un petit script php en ajax (très souvent) qui va nous dire où en est l'upload, en nous retournant le pourcentage d'avancement (tout simplement), avec cette valeur, on va pouvoir mettre en place une barre de progression très facilement.

pour commencer, le formulaire :

<?php $unique_id = uniqid(); //id unique de notre formulaire ?>
 
<!-- iframe caché en javascript dans laquelle se fait l'upload, elle affichera le message de confirmation / ou erreur à la fin de l'upload -->
<iframe frameborder="0" border="0" id="upload_to" name="upload_to" style="width: 100%; border:none; border-color: #fff;" scrolling="no"></iframe>
 
<!-- le formulaire d'upload -->
<form id="upload_form" enctype="multipart/form-data" action="upload.php" method="post" target="upload_to">
<input type="hidden" name="APC_UPLOAD_PROGRESS" id="progress_key" value="<?php echo $unique_id?>"/>
<div id="progressouter">
	<div id="progressinner"><span id="progression_percent">0&nbsp;%</span></div>
</div>
<p><input id="file" type="file" name="file" size="30" /></p>
<p><input type="submit" value="valider" /></p>
</form>

le bout de php au début, permet de donner un id unique au formulaire
il est renseigné dans le champ "APC_UPLOAD_PROGRESS" ceci permet au système de donner un id à l'upload en cours, ce qui nous permettra de consulter la progression en le connaissant (l'id).

l'iframe n'a rien de spéciale, elle est caché en javascript (voir plus bas).

le formulaire contient l'HTML de la barre de progression (la div progressouter, on pourrait la mettre ailleurs, chacun fait ce qu'il veut. et le champ hidden APC_UPLOAD_PROGRESS comme dit plus haut, obligatoire pour le suivi de l'upload.

passons maintenant à notre script d'upload : upload.php
l'upload en lui même n'est pas vraiment notre sujet du jour, donc, je prends l'exemple d'upload le plus simple au monde (donné sur php.net)

$uploaddir = '/var/www/uploads/';
$uploadfile = $uploaddir . basename($_FILES['file']['name']);
 
if (move_uploaded_file($_FILES['file']['tmp_name'], $uploadfile)) {
    echo "File is valid, and was successfully uploaded.\n";
} else {
    echo "Possible file upload attack!\n";
}

on aura besoin du fameux script qui retourne le pourcentage d'avancement de l'upload : progress.php

header("Cache-Control: no-cache"); //utile pour IE (problème avec l'ajax)
//progression
if(isset($_GET['progress_key'])) {
    $upload = apc_fetch('upload_'.$_GET['progress_key']);
    $percent = 1000;
    if ($upload) {
        if ($upload['done'])
            $percent = 100;
        elseif ($upload['total'] == 0)
            $percent = 0;
        else
            $percent = $upload['current'] / $upload['total'] * 100;
    }
 
    echo number_format($percent, 2);
}

c'est presque fini, il ne reste plus que le javascript :

function getProgress(){
    var count = Math.random(); /// Math.random sélectionne un nombre entre 0 et 1 ( ex: 0.6489534931546957) pour IE aussi (même si le header no-cache devrait suffire)
    $.ajax({
        type: "GET",
        url: "/progress.php?progress_key=<?php echo($unique_id)?>&count="+count,
        success: function(percent) {
            if (percent <= 100){
                $("#progressinner").css("width", percent+"%");
                $("#progression_percent").text(percent+" %");
            }
            if (percent < 100){
                setTimeout("getProgress()", 100);
            }
            if (percent == 100){
                $("#upload_to").show("slow");
                $("#file").val('');
            }
        }
    });
}
 
function startProgress(){
    $("#progressouter, #progression_percent").show(200);
    setTimeout("getProgress()", 1000);
}
 
 
$(document).ready(function(){
    $("#upload_to").hide();
    $('#upload_form').submit(function () {
        startProgress();
    });
});

en gros (très gros même) ce js va cacher l'iframe au chargement de la page, et à la validation du formulaire, il va lancer la fonction startProgress(), qui elle, va afficher la barre de progression et lancer régulièrement getProgress, qui elle, fait un appel ajax à notre script progress.php et lui indiquant l'unique id généré tout au début de la page et en fonction du retour, elle va ajuster la largeur de la barre de progression.

si vous avez des questions, n'hésitez pas à les poser dans les commentaires.

Share
24jan/110

Lancement de www.snippets.fr

j'ai le plaisir de vous annoncer le lancement d'un nouveau site, http://www.snippets.fr.

comme son nom l'indique, ce site est là pour regrouper des snippets dans différents langages (php seulement pour l'instant) et sur des tehcno que j'utilise au quotidien (Drupal, Magento, WordPress, etc.) dans le boulot mais aussi pour mes projets perso.

si vous avez des snippets qui trainent, vous savez où les contribuer maintenant :)

Bon surf.

Share
9juin/092

convertir un array en utf8

dans un précédent article nous avons vu comment convertir un texte en utf8.

aujourd'hui on va voir comment faire la même chose mais avec un tableau, sans passer par un foreach, ni aucune autre boucle.

pour cela nous allons utiliser une seule fonction qui convertira ce qu'on lui donne en entrée en utf8.
pour l'instant elle va savoir gérer, les chaînes de caractères et les tableaux.

function toUTF8($param)
{
    if(is_array($param)) {
        array_walk_recursive($param, create_function('&$item, $index', '$item = toUTF8($item);'));
        return $param;
    }
 
    mb_detect_order('UTF-8, ISO-8859-15, ISO-8859-1, Windows-1252');
    //parfois si le dernier caractère de la chaine est accentué, la conversion peut foirer,
    //donc on force avec un caractère qui ne l'est pas.
    //(astuce trouvée sur les commentaires de la doc sur php.net)
    $param .= '_';
    $currentCharset = mb_detect_encoding($param);
 
    if ($currentCharset != 'UTF-8') {
        $param = mb_convert_encoding($param, 'UTF-8', $currentCharset);
    }
 
    return substr($param, 0, strlen($param)-1);
}

et voilà, cette fonction convertira array ou string en utf8 sans brancher...

en bonus voici une fonction somme que j'ai trouvé dans les commentaire de la doc sur php.net (une sorte de coup de coeur pour moi :-D )

function sum(){
    $s=0;
    foreach(func_get_args() as $a) $s+= is_numeric($a)?$a:0;
    return $s;
};
 
print sum(1,2,3,4,5,6); // will return 21
print sum(3,2,1); // will return 6
print sum(false,array(),5,5); // will return 10

trop fort non ?

Share
8mai/090

protéger un ou plusieurs fichiers par htaccess

Nous avons vu dans précédent article comment protéger un répertoire avec htaccess, c'est l'utilisation la plus courante de cette technique, mais ici nous allons nous intéresser a comment faire la même chose mais pour protéger uniquement un ou quelques fichiers d'un répertoire, c'est à dire, dans le même répertoire, certains fichiers seront protégés mais pas d'autres.

pour protéger un seul fichier voici ce qu'il faut mettre dans le .htaccess :

<files fichier.ext>
require valid-user
</files>

pour en protéger plusieurs :

<files fichier1.ext fichier2.ext fichier3.ext>
require valid-user
</files>

cette syntaxe est a utiliser en complément de celle expliquée dans l'autre article bien sûr.

bonne protection de fichiers...

Share
14mai/087

Comment installer fileinfo sous debian

Les fonctions de l'extension FileInfo essaient de savoir le type de contenu et l’encodage d’un fichier en regardant certaines séquences d’octet "magique" à des positions spécifiques à l’intérieur du fichier. Bien qu'il ne s'agit pas d'une approche infaillible, la méthode heuristique effectue un très bon travail.

le problème avec cette extension c'est qu'elle est un peu dur à installer, en réalité pas si dur que ça, il suffit de prendre le temps de le faire. Il faut juste savoir qu'un simple apt-get install php5-fileinfo ne suffira pas, tout simplement parce qu'il n'existe pas de paquet debian pour cette extension (pas encore...).

Donc pour l'installer, voici la procédure :
Il faut d'abord installer PEAR :

apt-get install php-pear

ensuite il faut installer php5-dev si ce n'est pas déjà fait, ceci installera phpize ce qui nous évitera l'erreur :

sh: phpize: command not found
ERROR: `phpize' failed

installation de php5-dev :

apt-get install php5-dev

c'est presque bon mais pas encore :
maintenant il faut installer libmagic pour nous éviter une erreur lors de l'installation de fileinfo :

apt-get install libmagic-dev

maintenant tout est bon, nous allons enfin pouvoir lancer l'installation de notre extension :

pecl install fileinfo

Voilà, maintenant fileinfo est installée, nous allons pouvoir vérifier les types mime des fichiers avec des méthodes plus fiables ;-)

Normalement tout devrait fonctionner maintenant, mais il ce peut que l'extension ne soit pas activée comme il faut, dans ce cas il faudra créer un fichier fileinfo.ini dans /etc/php5/apache2/conf.d avec le contenu suivant :

extension=fileinfo.so

reloader apache avec /etc/init.d/apache2 reload et le tour est joué :)

Share