Catégorie : développement – divers

PhpStorm, Windows / WAMP et xdebug : howto – la solution

Si jamais vous êtes comme moi, et que vous n’avez pas réussi à faire fonctionner PhpStorm avec xdebug sous Windows avec WAMP, vous avez peut-être le même problème que moi à savoir : le serveur Apache semble mal configuré – ou configurable, et incapable d’utiliser Php correctement avec xdebug.

Je passe toutes les étapes de configuration « classiques », parce qu’elles sont simples et bien documentées – y compris dans PhpStorm. Malgré tout ça, il se peut que cela ne fonctionne pas.

La solution :

Solution PhpStorm RunDebug Configurations pour Windows - WAMP

En fait il faut configurer PhpStorm pour qu’il ne passe pas par Apache, mais qu’il lance le serveur Php intégré (si, Php a un serveur HTTP, cherchez dans la documentation).

Et ainsi, le déboguage en ligne fonctionnera.

C’est grâce à cette vidéo que j’ai eu l’idée d’essayer :

http://www.youtube.com/watch?v=LUTolQw8K9A

Bien sûr, si vous essayez xdebug sous Linux, vous aurez nettement moins de difficultés :).

CodinGame challenge : les résultats

Vous pourrez trouver la totale ici.

Je cite :

Sur les 3245 inscrits, 1124 ont tenu bon jusqu’à la fin. Et il faut dire que le niveau était plutôt excellent. Avec un 3e exercice que certains codeurs de notre connaissance auraient qualifié de « torture japonaise », le challenge nécessitait de jongler entre plusieurs compétences complémentaires.

Ils ont tout à fait raison, vu que… je ne l’ai pas fait !

Vous pouvez voir le classement complet ici.

Moi je suis le pseudo SurferIX, position 120 :

120 - SurferIX - 65% - 03:48:46 - PHP, C

Et mon code fait en 3 heures 48 ici.

De la nourriture pour le cerveau !

Pris ici, et traduit en français par moi même.

C’est mon site favori.

Je le visite presque tous les jours.

Il n’est pas « responsive ». Il n’est pas optimisé pour iPhone.
Il a l’air flou sur un affichage de type Retina.
Il n’utilise pas le tout dernier framework HTML5/CSS3.
Il n’a pas un « rythme vertical réfléchi pour être agréable ».
Les fontes n’ont rien d’original. Ni Le skeuomorphique ni plat.
Il n’a pas son propre favicon.
Il n’a aucune application native Twitter ou Instagram.
Il n’utilise ni d’AJAX ni de SCRUM ou de node.js ou de Sinatra.
Il n’a pas sa propre API ou son suivi RSS, et pas de VC funding.
Il n’a jamais été numéro un sur un blog technique connu et n’a jamais gagné un seul concours.

Il me dit comment faire la soupe du jour.

Une information donnée gratuitement, qui est pratique pour la personne qui le lit.

C’est ça, le web design.

Développement : Coding contest !

Challenge de codeurs !

C’est pour le fun, essayez vous aussi 

Le principe est simple

Vous aurez deux puzzles de programmation à résoudre.

Pour ce faire, vous pourrez choisir votre langage favori parmi ceux-ci : Java, C, C++, C#, Javascript, PHP, Python, Ruby, Objective-C, Haskell and Go.
La durée moyenne d’un challenge est de 2 heures et 30 minutes.

J’y serai, le 28 septembre !

Php : challenge ASCII art

J’ai fait un pari. Petit challenge à réaliser : faire un script (peu importe le langage) qui prend en paramètre un fichier image, et qui en sort de l’ASCII art.
Il faut qu’il soit rapidement paramétrable sur la taille des fontes.

Je l’ai fait « théorique » en 59 minutes, mais entièrement fonctionnel en une heure trente. J’ai fait deux scripts : un qui génère le fichier des fontes, et le principal qui lit le fichier image des fontes, et le fichier image en paramètre, et sort de l’ASCII art.

Exemple de résultat (si si c’est bien du texte, vous pouvez le sélectionner et copier coller en tant que texte !) :

BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBMBBBBBBBBBBBB
BBBBBBBBBBBBBBBBBBBBBBBBBBBBBB¨ MBBBBBBMM0BBB
BBBBBBBBBBBBBBBBBBBBBBBBBP'`BB  ,BBBP¨    MBB
BBBBBBBBBBBBBBBBBBBBBBBBB&  %BMBPBBL  ,a  ¨BB
BBBBBBBBBBBBBBBBBBBBBBBBBB  jBB  MBBaBBP   BB
BBBBBBBBBBBBBBBBBBBBBBBBPM   BB  ¨BBB^  ,  0B
BBBBBBBBBBBBBBBBBBBBBBP`     BBb  BB'  mB  jB
BBBBBBB@P'BBBBBB@M@BBB   mB  $BK  0B  jBP  ¨B
BBBBBBBK  BBBP^`   MBB  dBB  MBB  jB   ¨ L,aB
B^¨ 'BBB  %BB  ,a   BB  &BBL  BB   Bh  ,WBBBB
B    ¨BB  jBB,mBM^  $B  'BBF  BBL  BBBBBBBBBB
BL    `BL  BBBP¨    jB   ^^   %B&mBBBBBBBBBBB
B&  w  ¨&  BBP  wB   B&    wamBBBBBBBBBBBBBBB
BB  %w     MBL  BB¨  BBBwamBBBBBBBBBBBBBBBBBB
BB  MBw    ¨BK  ¨`, ,&BBBBBBBBBBBBBBBBBBBBBBB
BBL  BBN    BB,  aBBBBBBBBBBBBBBBBBBBBBBBBBBB
BB&  BBBh   0BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBB  MBBBhwmBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
BBB  OBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB

Ne regardez pas la suite si vous voulez essayer de le faire pour vous !

<?php
function usage_et_exit($message = '', $exit_error = -1) {
    global $argv;
    if ($message != '') {
        echo $message."\n";
    }
    echo $argv[0]." {image gif reference} {image noir et blanc jpg}\n";
    exit($exit_error);
}

function noir_ou_blanc($r, $g, $b) {
    /* http://stackoverflow.com/questions/254388/how-do-you-convert-an-image-to-black-and-white-in-php */
    if (((0.299*$r) + (0.587*$g) + (0.114*$b))> 0x7F) {
        return 0xFFFFFF;
    } else {
        return 0x000000;
    }
}

function cherche_meilleure_correspondance(
    $img_src, $x, $y, $img_fonts, $font_size, $tab_base
) {
    $meilleur = -1;
    $retour = '';
    foreach ($tab_base as $idx => $ch) {
        $match = 0;
        for ($t_y=0; $t_y<$font_size; $t_y++) {
            for ($t_x=0; $t_x<$font_size; $t_x++) {
                if (imagecolorat($img_src, $t_x+$x, $t_y+$y)
                    != imagecolorat(
                        $img_fonts,
                        ($idx*$font_size) + $t_x, $t_y
                    )
                ) {
                    $match++;
                }
            }
        }
        if ($match>$meilleur) {
            $retour = $ch;
            $meilleur = $match;
        }
    }
    return $retour;
}

function convert_img_noir_et_blanc($filename, $img)
{
    list($width, $height, $type, $attr) = getimagesize($filename);
    /* Conversion en noir et blanc */
    for ($y=0; $y<$height; $y++) {
        for ($x=0; $x<$width; $x++) {
            $rgb = imagecolorat($img, $x, $y);
            $r = ($rgb >> 16) & 0xFF;
            $g = ($rgb >> 8) & 0xFF;
            $b = $rgb & 0xFF;
            $nb = noir_ou_blanc($r, $g, $b);
            imagesetpixel($img, $x, $y, $nb);
        }
    }
}

$tab_base = array(
    '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c',
    'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
    'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
    '5', '6', '7', '8', '9', '&', '\'', ',', ';', ':', '?', '.', '/', '!',
    '%', '^', '¨', '$', '~', '#', '(', ')', '[', ']', '|', '-', '`', ' '
);
$font_size = 14;
$min_width  = 400;
$min_height = 400;

if ($argc!=3) {
    usage_et_exit("Arguments invalides", -1);
}

$img_tmp = imagecreatefromstring(file_get_contents($argv[1]));
$width = imagesx($img_tmp);
$height = imagesy($img_tmp);
$img_fonts = imagecreatetruecolor($width, $height);
imagecopy($img_fonts, $img_tmp, 0, 0, 0, 0, $width, $height);
imagedestroy($img_tmp);
unset($img_tmp);
if ($img_fonts===false) {
    usage_et_exit("Erreur chargement de ".$argv[1], -1);
}

/* Conversion en noir et blanc des fontes */
convert_img_noir_et_blanc($argv[1], $img_fonts);
imagepng($img_fonts, './resultat_fonts.png', 0);

list($width, $height, $type, $attr) = getimagesize($argv[2]);
if ($width<$min_width) {
    usage_et_exit("Largeur trop petite de ".$argv[1].", taille min = ".$width_min, -1);
}
if ($width<$min_height) {
    usage_et_exit("Hauteur trop petite de ".$argv[1].", taille min = ".$width_min, -1);
}

$img_src = imagecreatefromjpeg($argv[2]);
if ($img_src===false) {
    usage_et_exit("Erreur chargement de ".$argv[2], -1);
}
convert_img_noir_et_blanc($argv[2], $img_src);
/* Ok on a l'image en noir et blanc. Parcourir toute l'image */
imagepng($img_src, './resultat_noir_et_blanc.png', 0);

$y = 0;
$max_result = 0;
while (($y + $font_size) < $height) {
    $x = 0;
    while (($x + $font_size) < $width) {
        echo cherche_meilleure_correspondance(
            $img_src, $x, $y, $img_fonts, $font_size, $tab_base
        );
        $x += $font_size;
    }
    echo "\n";
    $y += $font_size;
}
echo "Done.\n";
?>

Et le fichier qui génère les fontes (22 minutes de perdues à le faire…) :

<?php
$tab_base = array(
    '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N',
    'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c',
    'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
    'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
    '5', '6', '7', '8', '9', '&', '\'', ',', ';', ':', '?', '.', '/', '!',
    '%', '^', '¨', '$', '~', '#', '(', ')', '[', ']', '|', '-', '`', ' '
);
$x=0;
$font_size = 14;
$width = count($tab_base)*$font_size;
echo 'width='.var_export($width,true)."\n";
$height = $font_size*4;
$img = imagecreatetruecolor($width, $height);
if ($img===false) {
    throw new Exception("Erreur");
}
imagefilledrectangle($img, 0, 0, $width, $height, 0xFFFFFF);
foreach ($tab_base as $idx => $char) {
    $ok = imagettftext(
        $img,
        $font_size, 0,
        $idx * $font_size, $font_size,
        0x000000,
        './consola.ttf', $char
    );
}
imagegif($img, './test.gif');
echo "Done.\n";
?>

Symfony 2 : [Semantical Error] The annotation « @ManyToMany » in property … was never imported.

Si jamais un jour, vous tentez de déclarer à la main une relation de type OneToOne, OneToMany ou ManyToMany et que vous avez une erreur de ce genre :

[Semantical Error] The annotation "@ManyToMany" in property MaSociete\PersoBundle\Entity\MaClasse::$proprietes was never imported. Did you maybe forget to add a "use" statement for this annotation?

Alors vous vous êtes sûrement aidé, comme moi, de la documentation officielle qui donne ces exemples, que je copie colle ici :

<?php
/** @Entity **/
class User
{
    // ...

    /**
     * @ManyToMany(targetEntity="Group", inversedBy="users")
     * @JoinTable(name="users_groups")
     **/
    private $groups;

    public function __construct() {
        $this->groups = new \Doctrine\Common\Collections\ArrayCollection();
    }

    // ...
}

/** @Entity **/
class Group
{
    // ...
    /**
     * @ManyToMany(targetEntity="User", mappedBy="groups")
     **/
    private $users;

    public function __construct() {
        $this->users = new \Doctrine\Common\Collections\ArrayCollection();
    }

    // ...
}

Si cela ne fonctionne pas et que vous avez cette erreur :

[Semantical Error] The annotation "@ManyToMany" in property MaSociete\PersoBundle\Entity\MaClasse::$proprietes was never imported. Did you maybe forget to add a "use" statement for this annotation?

Alors c’est qu’il suffit simplement d’ajouter le mot ORM\.

Ainsi mon code qui ne fonctionnait pas :

<?php
/**
 * @ManyToMany(targetEntity="Partenaire", inversedBy="personnes")
 * @JoinTable(name="personne_partenaire")
 **/
?>

Et le code qui fonctionne :

<?php
/**
 * @ORM\ManyToMany(targetEntity="Partenaire", inversedBy="personnes")
 * @ORM\JoinTable(name="personne_partenaire")
 **/
?>

Symfony 2 et vim : coloration syntaxique twig / twig syntax highlighting

Comment faire pour mettre en place la coloration syntaxique sous vim ?

Rien de plus simple : il faut aller ici.

Et ensuite vous allez dans votre répertoire de configuration vim, qui est le plus souvent : .vimrc.

De là, vous faites un copier coller « à la main » des fichiers de configuration dans les répertoires adéquats.

N’hésitez pas pour une chose : si les répertoires de destination n’existent pas, créez-les !

Bien sûr, il y a des façons plus propres de procéder, notamment en utilisant vimplugin, mais je l’ai fait « vite », et cela a très bien fonctionné cinq fois, sur cinq PC et distributions différentes, y compris sous Cygwin.

Drupal : code pour les liens avec des URLs dynamiques

Drupal : comment s’adapter à une migration si le site n’est plus à la racine ?

Dans les modules, activation du module « Php filter », afin que le code Php soit exécuté.
Et dans le texte qu’il y a dans un bloc « menu », par exemple, vous pourriez vous inspirer d’un code comme celui-ci (sachant qu’il vous faut absolument revoir l’indentation, qui n’est pas acceptable pour un code digne de ce nom) 🙂  :

<?php /* Ce code sert à générer les URLs
 * de manière dynamique, afin que si l'installation
 * Drupal est dans un sous-répertoire, les liens
 * soient "automatiquement" adaptés, via
 * le code "'absolute' => TRUE", 
 */ ?>
<ol>
    <li>
        <?php echo l(t('Menu1'),
            'lien1',
            array( 'absolute' => TRUE, 'query' => array()
        )); ?>
    </li>
    <li>
        <?php echo l(t('Menu2'),
            'lien2',
            array( 'absolute' => TRUE, 'query' => array()
        )); ?>
    </li>
    <li>
        <?php echo l(t('Menu3'),
            'lien3',
            array( 'absolute' => TRUE, 'query' => array()
        )); ?>
    </li>
    <li>
        <?php echo l(t('Menu4'),
            'lien4',
            array( 'absolute' => TRUE, 'query' => array()
        )); ?>
    </li>
</ol>

DNS et noms de domaine : one and one, 1and1 … sous DNS 10 max !

Petite information (valable au jour même de ce billet) :

Si vous achetez des noms de domaine :

  • chez ovh.fr vous ferez tout ce que vous voulez avec vos noms de domaines : c’est long mais c’est le meilleur rapport qualité prix ;
  • chez gandi.net vous ferez tout ce que vous voulez avec vos noms de domaines et vous pourrez même faire des « modèles » de vos configurations DNS pour les appliquer partout (pratique quand on a plein de noms de domaines) ;
  • chez oneandone.fr (ou 1and1.fr) vous serez limité à dix sous domaines pour la totalité de votre compte !

Exemple concret : j’ai un partenaire, pizzamis.fr qui a acheté son nom de domaine chez oneandone.fr (ou 1and1.fr).

Les sites que je fait sont très optimisés et se servent, notamment, de la fonctionnalité de séparation des sous domaines pour télécharger en parallèle (voir les conseils de YSlow).

Donc pour un site, j’ai les préfixes « s » comme « static » puis un chiffre de 1 à 4. Et les préfixes de la langue (« fr », « us » etc).

Donc pour ce partenaire, j’ai ces préfixes :

  • fr.pizzamis.fr
  • fr.s1.pizzamis.fr
  • fr.s2.pizzamis.fr
  • fr.s3.pizzamis.fr
  • fr.s4.pizzamis.fr

Cinq préfixes. Pour la version téléphone mobile, même chose : cinq préfixes.
Sur gandi, même chose que sur ovh : pas besoin de configurer les préfixes : on configure en mettant « * CNAME . » et tout fonctionne.

Ici, voici le résultat :

Limite 10 sous domaines chez 1and1

Oui oui vous avez bien lu :

10 utilisés sur 10 disponibles.

Après, à vous de juger, je dis ça, mais c’est un constat, tout est objectif !
Je n’ai pas dit de ne jamais aller chez oneandone.fr (ou 1and1.fr) 😉 !