Archives de catégorie : PHP

PHP : classer un tableau d’objets avec usort

En PHP il arrive de se retrouver avec un tableau d’objets qui n’est pas ordonné comme on le voudrait, il faut dans ce cas utiliser la fonction usort qui permet de trier un tableau en utilisant une fonction de comparaison.

Imaginons nous avons un tableau « $list » d’objets « User », contenant -entre autre- les propriétés « Date » et « Name », Date étant un objet DateTime et Name un string

Pour trier par date il faut créer et appeler la fonction suivante (l’exemple peux s’appliquer à n’importe quel tri)

//on déclare la fonction de tri
orderByDate($a, $b) {
    //retourner 0 en cas d'égalité
    if ($a->date == $b->date) {
        return 0;
    } else if ($a->date < $b->date) {//retourner -1 en cas d’infériorité
        return -1;
    } else {//retourner 1 en cas de supériorité
        return 1;
    }
}
//appel de la fonction avec notre tableau $list, $list contiendra ensuite les "User" trié par date.
usort($list, "orderByDate");

Si votre fonction est dans une classe et que vous l’utilisez depuis cette même classe, il faut l’appeler comme ceci :

usort($list, array($this, "orderByDate"));

Dans le cas d’une comparaison de chaine (comme par exemple ici sur le nom) on peux simplifier la syntaxe en utilisant la fonction strcmp de la manière suivante :

//on déclare la fonction
orderByName($a, $b) {
    return strcmp($a->name, $b->name);
}
//appel de la fonction
usort($list, "orderByName");

Prestashop (1.7) : Modifier des champs du formulaire de contact

Prestashop propose une page contenant un formulaire de contact afin que les visiteurs et utilisateurs de votre boutique puissent communiquer avec vous.
Cependant ce formulaire est peu personnalisable. Nous allons voir ci-dessous comment personnaliser ce formulaire. Notre exemple consistera en l’ajout d’un champ supplémentaire, mais la procédure permet permet de comprendre comment faire pour également supprimer ou modifier des champs existants.

Premièrement nous allons modifier le template du formulaire de contact afin de lui ajouter un champ.
Pour cela nous allons récupérer le template qui se situe dans votre thème (thème parent) ou bien directement dans le module « contactform » de prestashop.
Donc soit dans :

/themes/votre-theme-parent/modules/contactform/views/templates/widget/contactform.tpl

Soit dans

/modules/contactform/views/templates/widget/contactform.tpl

Et copier ce fichier dans votre theme enfant pour pouvoir le modifier proprement. C’est à dire dans :

/themes/votre-theme-enfant/modules/contactform/views/templates/widget/contactform.tpl

Vous pouvez maintenant faire vos modifications dans ce fichier. Par exemple pour ajouter un champ « Téléphone » (avec bien sur le html à adapter en fonction de votre thème et de la présentation souhaité) :

<div class="form-group row">
    <div class="col-md-12">
        <input class="form-control" name="phone" type="text" placeholder="Téléphone" value="{$contact.phone}">
    </div>
</div>

La seconde étape consiste à overrider le module contactform en étendant la classe « ContactForm » que vous trouverez dans le fichier :

/modules/contactform/contactform.php

Pour cela nous créons le fichiers suivant :

/override/modules/contactform/contactform.php

qui contiendra le code suivant (pour commencer) :

<?php

if (!defined('_PS_VERSION_')) {
    exit;
}

class ContactFormOverride extends Contactform {

//code à venir

}

On va à présent remplacer la ligne « //code à venir » en copiant telles quelles les 2 fonctions « getWidgetVariables » et « sendMessage » présentent dans le fichier d’origine :

/modules/contactform/contactform.php

On adapter les ligne de la fonction « getWidgetVariables » pour ajouter notre champs :

//...
//ajout de notre champ
$this->contact['phone'] = html_entity_decode(Tools::getValue('phone'));
//code d'origine
$this->contact['contacts'] = $this->getTemplateVarContact();
$this->contact['message'] = html_entity_decode(Tools::getValue('message'));
//etc...

Passons à la fonction « sendMessage » ou il va falloir modifier plusieurs partie du code, mais ces parties sont assez facile à repérer.
Il s’agit des 3 suivantes :

//debut de la fonction
$extension = array('.txt', '.rtf', '.doc', '.docx', '.pdf', '.zip', '.png', '.jpeg', '.gif', '.jpg');
$file_attachment = Tools::fileAttachment('fileUpload');
$message = trim(Tools::getValue('message'));
//ajout de notre champs
$phone = trim(Tools::getValue('phone'));
//...
//controle des différentes champs du formulaire
} elseif (!Validate::isCleanHtml($message)) {
    $this->context->controller->errors[] = $this->trans('Invalid message', array(), 'Shop.Notifications.Error');
} elseif (!Validate::isCleanHtml($phone)) {//contrôle de notre champ supplémentaire.
    $this->context->controller->errors[] = $this->trans('Téléphone invalide', array(), 'Shop.Notifications.Error');
}//....
$var_list = [
   '{order_name}' => '-',
   '{attached_file}' => '-',
   '{message}' => Tools::nl2br(stripslashes($message)),
   '{email}' => $from,
   '{product_name}' => '',
   '{phone}' => Tools::nl2br(stripslashes($phone)),//notre ajout
 ];

Il nous reste une dernière étape, il s’agit de modifier les templates correspondant à l’email transmis par le formulaire.
Vous pouvez retrouver ces template dans

/mails/fr/contact.html
/mails/fr/contact.txt

en adaptant la partie /fr/ selon votre language.
Vous devez copier ces fichier dans votre thème enfant :

/themes/votre-theme-enfant/mails/fr/contact.html
...

Et modifier leur contenus en ajoutant les informations concernant le nouveau champ.
Par exemple :

<span style="color:#333"><strong>Téléphone du client :</strong></span> {phone}<br /><br />

Normalement tout est bon !

PHP & Google Map API : Récupérer les détails d’une adresse (latitude, longitude, département, région…)

La semaine dernière nous avons vu une fonction permettant de calculer la distance entre deux coordonnées GPS, mais comment récupérer ces coordonnées (et d’autres informations) à partir d’une adresse ? Nous allons voir comment faire avec l’API google Map, il vous faudra tout d’abord récupérer une clé pour les appel à l’API (par ici).

Ensuite vous pouvez utiliser la classe et la fonction ci-dessous afin de récupérer les informations (adresse complète, latitude, longitude, vile, code postal, département, région, pays) correspondant à l’adresse passé au format texte.

class GmapApi {

    private static $apikey = 'VOTRE_API_KEY';

    public static function geocodeAddress($address) {
        //valeurs vide par défaut
        $data = array('address' => '', 'lat' => '', 'lng' => '', 'city' => '', 'department' => '', 'region' => '', 'country' => '', 'postal_code' => '');
        //on formate l'adresse
        $address = str_replace(" ", "+", $address);
        //on fait l'appel à l'API google map pour géocoder cette adresse
        $json = file_get_contents("https://maps.google.com/maps/api/geocode/json?key=" . self::$apikey . "&address=$address&sensor=false&region=fr");
        $json = json_decode($json);
        //on enregistre les résultats recherchés
        if ($json->status == 'OK' && count($json->results) > 0) {
            $res = $json->results[0];
            //adresse complète et latitude/longitude
            $data['address'] = $res->formatted_address;
            $data['lat'] = $res->geometry->location->lat;
            $data['lng'] = $res->geometry->location->lng;
            foreach ($res->address_components as $component) {
                //ville
                if ($component->types[0] == 'locality') {
                    $data['city'] = $component->long_name;
                }
                //départment
                if ($component->types[0] == 'administrative_area_level_2') {
                    $data['department'] = $component->long_name;
                }
                //région
                if ($component->types[0] == 'administrative_area_level_1') {
                    $data['region'] = $component->long_name;
                }
                //pays
                if ($component->types[0] == 'country') {
                    $data['country'] = $component->long_name;
                }
                //code postal
                if ($component->types[0] == 'postal_code') {
                    $data['postal_code'] = $component->long_name;
                }
            }
        }
        return $data;
    }

}

Par exemple en appelant la fonction de cette manière :

$data = GmapApi::geocodeAddress('151 avenue du pont trinquat 34070 Montpellier');
//on affiche les différente infos
echo '<ul>';
foreach ($data as $key=>$value){
    echo '<li>'.$key.' : '.$value.'</li>';
}
echo '</ul>';
/* va afficher
address : 151 Avenue du Pont-Trinquat, 34000 Montpellier, France
lat : 43.6008177
lng : 3.8873392
city : Montpellier
department : Hérault
region : Occitanie
country : France
postal_code : 34000
*/

On peux maintenant utiliser cette fonction pour trouver la distance entre 2 adresses, grâce à notre fonction de l’article précédent. Par exemple :

$data1 = GmapApi::geocodeAddress('151 avenue du pont trinquat 34000 montpellier');
$data2 = GmapApi::geocodeAddress('Avenue des cévennes 30360 vézénobre');
echo round(Misc::distance($data1['lat'], $data1['lng'], $data2['lat'], $data2['lng'])).' Km';
//Affiche : 54 Km

PHP : Calcul de la distance entre 2 coordonnées GPS (latitude, longitude)

La fonction toute prête afin de pouvoir la retrouver facilement, pas plus d’explications, c’est des maths, ça pique la tête !

class Misc {
    /**
     * Retourne la distance en metre ou kilometre (si $unit = 'k') entre deux latitude et longitude fournit
     */

    public static function distance($lat1, $lng1, $lat2, $lng2, $unit = 'k') {
        $earth_radius = 6378137;   // Terre = sphère de 6378km de rayon
        $rlo1 = deg2rad($lng1);
        $rla1 = deg2rad($lat1);
        $rlo2 = deg2rad($lng2);
        $rla2 = deg2rad($lat2);
        $dlo = ($rlo2 - $rlo1) / 2;
        $dla = ($rla2 - $rla1) / 2;
        $a = (sin($dla) * sin($dla)) + cos($rla1) * cos($rla2) * (sin($dlo) * sin($dlo));
        $d = 2 * atan2(sqrt($a), sqrt(1 - $a));
        //
        $meter = ($earth_radius * $d);
        if ($unit == 'k') {
            return $meter / 1000;
        }
        return $meter;
    }
}

Exemple d’utilisation :

echo round(Misc::distance(48.86417880,2.34250440,43.6008177,3.8873392), 3);//affiche 597.833 (pour 597,833 km entre les deux coordonnées fournit)

Il s’agit bien entendu de distance à vol d’oiseau.

L’article suivant explique comment obtenir les coordonnées latitude et longitude correspondant à une adresse grâce à l’API Google Map.

Rendez vous ici pour faire le calcul directement en MySql et dans Doctrine

source : http://www.phpsources.org/scripts459-PHP.htm

PHP : Remplacer du texte dans un fichier

Après avoir vu comment créer un fichier et écrire dedans en php, en continuant l’exemple d’un installateur de site, on peux aussi avoir besoin de modifier le texte d’un fichier, par exemple pour configurer des url dans un fichier « .htaccess ». Le code ci-dessous permet de le faire facilement :

class Misc {
    /**
     * Va remplacer toutes les chaines $find par $replace dans le fichier $file
     */

    public static function replaceInfile($file, $find, $replace) {
        if ($find != $replace) {
            //recupere la totalité du fichier
            $str = file_get_contents($file);
            if ($str === false) {
                return false;
            } else {
                //effectue le remplacement dans le texte
                $str = str_replace($find, $replace, $str);
                //remplace dans le fichier
                if (file_put_contents($file, $str) === false) {
                    return false;
                }
            }
        }
        return true;
    }
}

L’utilisation se faisant de cette manière :

if (!Misc::replaceInfile('../.htaccess', 'ancienne chaine', 'nouvelle chaine')) {
   //gestion erreur
}

Comme dans plusieurs articles précédents, pour ce code, j’ai imaginé cela sous la forme d’une fonction statique placé dans une classe Misc qui contiendrait diverses fonctions utilitaires

WordPress : Réécriture d’un paramètre dans une URL

Exemple de code wordpress permettant de transformer une url avec un paramètre du type « ?param=slug-param » en une url réécrite plus « propre »

Grace à ce code on va transformer
« https://numa-bord.com/custom-slug/slug-post/?param=slug-autre-post »
en
« https://numa-bord.com/custom-slug/slug-post/slug-autre-post »

add_action('init', 'yoursite_init');

function yoursite_init() {
    global $wp, $wp_rewrite;
    $wp->add_query_var('custom_param');
    $wp_rewrite->add_rule('custom-slug/([^/]+)/([^/]+)', 'index.php?custom_param=$matches[2]&post_type=custom-type&name=$matches[1]', 'top');

    // activer seulement la première fois
    //$wp_rewrite->flush_rules(false);
}

Dans le template, on peux récupérer notre paramètre de la façon suivante :

$param = get_query_var('custom_param');

C’est une technique qui permet de faire pas mal de chose, l’exemple ci dessus pourrait permettre de comparer deux « post ».
Plus concrètement sur un site ayant des véhicules en « custom post type », permettre de comparer les caractéristiques de deux d’entre eux avec une url de ce type :
https://numa-bord.com/comparateur/vehicule1/vehicule2

Snippet PHP : Uploader une image en provenance d’un formulaire

Exemple d’une fonction permettant de gérer l’upload d’une image en provenance d’un formulaire. Permet de la renommer et de la placer dans le répertoire voulus en fonctions des paramètres passés. Attention ici on contrôle uniquement le fait que ce soit une image, si on à des contraintes sur la taille du fichier ou les extensions autorisées il faudra rajouter des vérifications.

Comme pour le snippet précédent on imagine cette fonction dans une class « Misc » qui pourrait contenir d’autre fonctions utilitaires variées.

class Misc {
    /**
     * uploade le fichier image en provenance du input "file" ayant pour nom $fieldName et donne le nom $imgName à l'image
     * retourne le nouveau dossier/nom.ext de l'image si upload ok, sinon false
     */

    public static function uploadImg($fieldName, $imgName, $target_dir = "../images/") {
        if (isset($_FILES[$fieldName]) && $_FILES[$fieldName]["name"] != "") {
            $ext = pathinfo($_FILES[$fieldName]["name"], PATHINFO_EXTENSION);
            $target_file = $target_dir . $imgName . '.' . $ext;
            //contrôle si c'est bien une image
            $check = getimagesize($_FILES[$fieldName]["tmp_name"]);
            if ($check !== false) {
                if (move_uploaded_file($_FILES[$fieldName]["tmp_name"], $target_file)) {
                    return $target_file;
                }
            }
        }
        return false;
    }
}

Utilisation (après l’envoi d’un formulaire ayant un input de type « file » ayant pour attribut « name » la valeur « logo ») :

Misc::uploadImg('logo', 'logo');//retourne le nouveau chemin et nom de l'image uploadé (ex : "../images/logo.png") ou false en cas d'erreur.

PHP : Importer les données dans une base depuis un fichiers .sql

Ci-dessous un script PHP permettant d’importer dans une base les données d’un fichier « export.sql ». Cela permet de créer les tables et d’insérer les données dans la base directement en PHP sans passer par l’import du fichier via le PhpMyAdmin

Ça peut être utile par exemple dans un « installeur » de site, dans la même idée de l’article précédent qui permettait de Créer une fichier de configuration en PHP

//effectuer la connexion à la base de données
$mysqli = new mysqli(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
//fichier contenant le sql
$lines = 'export.sql';
//initialisation des variables
$req = "";
$finRequete = false;
//pour chaque ligne du fichier
foreach ($lines as $line) {
    //on saute les commentaires
    if (
substr($line, 0, 2) == '--' || $line == '') {
        continue;
    }
    //on ajoute la ligne à la requête
    $req .= $line;
    //Permet de repérer quand il faut envoyer l'ordre SQL...
    if (substr(trim($line), -1, 1) == ';') {
        $finRequete = true;
    }
    //si requête terminé, on l'exécute et on recommence le traitement à partir de la ligne suivante
    if ($finRequete) {
        if (!$mysqli->query($req)) {
            echo "<div class='alert alert-danger'>Erreur : " . $mysqli->error . "<br>" . $req . "</div>";
        }
        $req = "";
        $finRequete = false;
    }
}

PHP : Créer un fichier et écrire dedans

Exemple de code permettant de créer et d’écrire dans un fichier en PHP. Un des cas courant de ce besoins est la création de fichiers de configuration. Le code suivant permet de créer le fichier « config.db.php » qui comme son nom l’indiquer contiendra les constantes PHP permettant la connexion à la base de données.

Imaginons qu’il s’agit d’une partie d’un installeur de site. On demande de remplir les informations de connexion à l’utilisateur dans un formulaire classique. Une fois soumis on contrôle les champs, on vérifie que la connexion fonctionne et dans ce cas, on créer le fichier de configuration.

Dans le code est utilisé le tableau $fields sensé contenir les informations envoyé par le formulaire (et préalablement contrôlé)

<?php
/*...traitement du formulaire posté retournant le tableau $fields...*/
//nom du fichier à créer.
$filename = 'config.db.php';
//creation du fichier si il n'existe pas et ouverture en écriture
$conf_file = fopen($filename, 'w');
//on écrit dans le fichier ligne par ligne
fwrite($conf_file, '<?php' . "\r\n");
fwrite($conf_file, 'define("DB_HOST","' . $fields['host'] . '");' . "\r\n");
fwrite($conf_file, 'define("DB_USERNAME","' . $fields['username'] . '");' . "\r\n");
fwrite($conf_file, 'define("DB_PASSWORD","' . $fields['password'] . '");' . "\r\n");
fwrite($conf_file, 'define("DB_NAME","' . $fields['name'] . '");' . "\r\n");
//fermeture du fichier
fclose($conf_file);

Snippet PHP : Générer une chaine aléatoirement

Exemple d’une fonction permettant de générer une chaine aléatoire, avec le nombre de caractères et les caractères utilisés paramétrable.

On imagine cette fonction dans une class « Misc » qui pourrait contenir d’autre fonctions utilitaires variées.

class Misc {

    /**
     * Générer une chaine aléatoire de $lenght caractères, utilisant les $characters
     */

    public static function randomString($length = 20, $characters = 'abcdefghijklmnopqrstuvwxyz0123456789') {
        $charactersLength = strlen($characters);
        $randomString = '';
        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characters[rand(0, $charactersLength - 1)];
        }
        return $randomString;
    }

}

Utilisation :

Misc::randomString();//retourne une chaine du type "8iplqu8fkz4d4ffn83sy"

PHP : Travailler avec les dates

PHP fournit les classe DateTime, DateTimeImmutable et DateInterval qui permettent de travailler et faire des calculs facilement sur les dates

On peux par exemple facilement trouver la date qu’il sera dans X jours de la façon suivante :

$start = new DateTimeImmutable('2017-06-25 09:00');//date de départ (25 jun 2017)
$end = $start->modify('+10 day');//10 jours plus tard
$end->setTime(0,0,0);//on passe l'horaire a 00:00:00
echo $end->format('d/m/Y H:i:s');//affiche : 05/07/2017 09:00:00

On peux aussi connaitre la différence (nombre de jours, mois) entre 2 dates

$start = new DateTimeImmutable('2017-06-25');//date de départ (25 juin 2017)
$end = new DateTimeImmutable('2017-08-31');//date de départ (31 aout 2017)
$interval = $start->diff($end);//on récupère la différence entre ces 2 dates
echo $interval->format('%a jours');//affiche : 67 jours
echo $interval->format('%m mois et %d jours');//affiche : 2 mois et 6 jours

Beaucoup de chose sont possible, ci-dessous on récupère le dernier jour du mois en cours, et le nombre de jours qui nous sépare de cette date

$now = new DateTime();//aujourd'hui
$end = new DateTime($now->format('Y-m-t'));//fin du mois
$interval = $now->diff($end);//on récupére la différence entre ces 2 dates
echo $interval->format('%a jours');//on affiche le nombre de jour entre ajourd'hui et la fin du mois

Pour plus d’informations il suffit de se reporter à la documentation PHP