Blogue professionnel de Mathias

Aller au contenu | Aller au menu | Aller à la recherche

mardi 4 décembre 2012

[PHP 4] Un extracteur d'adresses email

J'ai libéré avant-hier une petite application Web d'extraction d'adresses email. Je partage son code source sous les termes des licences GNU : LGPL 2.1 et CC By-NC.

C'est un script PHP en un seul fichier, qui sur la base d'un texte brut n'en garde que les adresses e-mail. Ce text brut peut être un copier-coller d'un document ODT (traitement de texte) ou TXT (par exemples). 

Ce « logiciel » comporte plusieurs options « nourries » de traitement des adresses collectées : caractère(s) qui sépare(nt) chaque adresse de la suivante, format HTML de sortie, ordre de sortie et bien sûr la suppression des doublons éventuels. 

Le formulaire d'envoi du texte brut est relativement accessible, avec évidemment des étiquettes (<label>) : vous pouvez activer chaque élément interactif (menu déroulant par exemple) en cliquant ou tabulant sur son texte associé, et non juste sur cet élément lui-même.

Les codes source dont je me suis inspirés sont crédités.

Historique 

Écrit fin 2008 et début 2009, probablement après la découverte fortuite d'un service nommé Tictacmail, dont les limitations me laisse sans voix, même dans ses versions payantes. Si vous n'y connaissez rien en programmation, sachez que les limitations d'un programme ou d'un service Web sont généralement commerciales : elles poussent l'utilisateur à s'inscrire ou à payer pour une version “premium”. À la base, le code et l'application fonctionnent très bien sans ces limitations ; il est plus compliqué d'intégrer des limitation à l'application que de la laisser sans ; en d'autres mots, le code informatique « tend vers l'infini » (si je puis m'exprimer ainsi). Mon but était donc de réaliser un concurrent direct de Tictacmail, mais sans ses limitations.

Il me semble avoir assez rapidement intégré la fonction de génération et de téléchargement d'un fichier CSV. Sauf que je me suis rendu compte que le répertoire n'était pas restreint à la session en cours (il me semble qu'une fonction PHP permet cela). Si deux internautes utilisaient simultanément l'application, l'un-e aurait pu voir le fichier de l'autre ou l'aurait écrasé. Inadmissible pour des choses aussi critiques que des adresses électroniques. Cette fonction est donc désactivée.

Dimanche 2 décembre 2012 : j'intègre un avertissement quant à une visite en HTTP, c'est-à-dire sans chiffrement dans la connexion entre votre machine et mon serveur. À moins que vous utilisiez la forme chiffrée de cette page, les adresses collectées voyageront en clair sur le réseau Internet entre leur envoi du serveur jusqu'à votre ordinateur. Pas très respecteux pour les titulaires de ces courriels… Je corrige aussi le code de gestion des erreurs, qui n'est pas sémantique.

Il subsiste au moins un bogue : des retour chariots <br /> ne sont pas interpétés dans le champ de texte final (ils y apparaissent).

Code complet de la page

<?php 

/* [fr] Extracteur d'adresses de courriel
* Ce logiciel est un script écrit en PHP 4, structuré en XHTML, et stylé en CSS.
* Fourni TEL QUEL (as is) SANS AUCUNE GARANTIE
*
* Mise-à-jour du dimanche 2 décembre 2012 :
* Codé il y a bien longtemps, je mets maintenant ce script en open-source,
* (accès via ?source dans l'URL), bien qu'il reste des morceaux non utilisés car issus de
* fonctionnalités non mises au point et/ou mal codées.
* Raison n°1 de la diffusion : prouver que je ne récupère pas les adresses collectées.
* Raison n°2 : montrer une (petite) réalisation - bien que je programme plus depuis près de 2 ans
* (mon agenda est parasité par la poursuite-bâillon des sociétés Cxxxxxk & Vivaldi-Avocats)
* Raison n°3 : permettre la diffusion de cet outil, alternative gratuite au service tictacmail.
*
*
*
*
*/


if(isset($_GET['source'])) // petit bout de code trouvé sur le siteduzero.com
{
show_source(__FILE__);
exit;
}

//error_reporting(E_ALL);
//ini_set('display_errors', '1');

function pre_print_r($tab)
{
echo "<pre>";
print_r($tab);
echo "</pre>";
}
function pre_var_dump($var)
{
echo "<pre>";
var_dump($var);
echo "</pre>";
}


/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
/* ----- DEBUT partie configuration ----- ----- ----- ----- ----- ----- ----- ----- ----- -- */
/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
/* ----- vous pouvez depuis ici modifier facilement certains paramètres ----- ----- ----- -- */
/* dossier d'export pour le fichier .csv qui sera toujours le seul dans ce répertoire */
$dossierCSV = "export_csv"; // fonction n'est plus utilisée car dossier non privé
// TODO : faire en sorte que ce dossier ne soit visible que par l'internaute, inaccessible aux autres
// (acteullement n'importe qui y avait accès, ce pkoi j'ai désactivé cette fonction)
/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
/* ----- FIN partie configuration ----- ----- ----- ----- ----- ----- ----- ----- ----- ---- */
/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */



/* A FAIRE :
* import depuis un fichier : réportoire qui va avec
* conservation du choix : http://www.siteduzero.com/tutoriel-3-14543-php-et-les-formulaires.html#ss_part_3
* cette conservation du choix du formulaire ne fonctionne que PARTIELEMENT pour le moement
* cookie de sauvegarde de config
* compteur live pour pas d'interférence ?
* export en .txt
* séparateur personnel
* taille fichier : virgule à la place du point anglo-saxon
* faire en sorte que les <br /> soient interprétés dans un textarea
*/


/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
/* ----- DEBUT partie référencement ----- ----- ----- ----- ----- ----- ----- ----- ----- -- */
/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
function afficheUnDomaineTTM()
{
// liste des intitulés
$DomainesTTM = array(
"tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com",
"tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com",
"tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com",
"tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com",
"tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmailc.om", "tictacmai.lcom", "www.tictacmail.com", "www.tictacmail.com", "www.tictacmail.com", "ww.wtictacmail.com", "wwwt.ictacmail.com", "www.tictacmail.com", "www.tictacmail.com", "www.tictacmail.com", "wwww.tictacmail.com", "ww.tictacmail.com", "www.tictacmail.com", "www.tictacmail.com", "www.tictacmail.com", "qqq.tictacmail.com", "sss.tictacmail.com", "xxx.tictacmail.com", "vvv.tictacmail.com", "www.tictacmail.com", "www.tictacmail.com", "www.tictacmail.com", "itctacmail.com", "tcitacmail.com", "titcacmail.com", "ticatcmail.com", "tictcamail.com", "tictamcail.com", "tictacamil.com", "tictacmial.com", "tictacmali.com", "tictacmai.lcom", "tictacmailc.om", "tictacmail.ocm", "tictacmail.cmo", "(ictacmail.com", "rictacmail.com", "gictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "yictacmail.com", "-ictacmail.com", "t_ctacmail.com", "tuctacmail.com", "tkctacmail.com", "toctacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tçctacmail.com", "tiftacmail.com", "tixtacmail.com", "tivtacmail.com", "tic(acmail.com", "ticracmail.com", "ticgacmail.com", "ticyacmail.com", "tic-acmail.com", "tict&amp;cmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictécmail.com", "tictzcmail.com", "tictqcmail.com", "tictafmail.com", "tictaxmail.com", "tictavmail.com", "tictacpail.com", "tictaclail.com", "tictac:ail.com", "tictacùail.com", "tictacm&amp;il.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacméil.com", "tictacmzil.com", "tictacmqil.com", "tictacma_l.com", "tictacmaul.com", "tictacmakl.com", "tictacmaol.com", "tictacmaçl.com", "tictacmaio.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmail.com", "tictacmaik.com", "tictacmai;.com", "tictacmaim.com", "tictacmail.fom", "tictacmail.xom", "tictacmail.vom", "tictacmail.cçm", "tictacmail.cim", "tictacmail.clm", "tictacmail.cpm", "tictacmail.càm", "tictacmail.cop", "tictacmail.col", "tictacmail.co:", "tictacmail.coù"
);

// choix au hasard de 1 élément dans l'array
$unDomaineTTM = array_rand($DomainesTTM);

// on renvoit un intitulé de façon aléatoire
return $DomainesTTM[$unDomaineTTM];
} // FIN function afficheUnDomaineTTM
/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
/* ----- FIN partie référencement ----- ----- ----- ----- ----- ----- ----- ----- ----- ---- */
/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */


/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
/* ----- DEBUT du script (partie principale) ----- ----- ----- ----- ----- ----- ----- ----- */
/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
/* on créé un tableau qui va contenir les éventuelles erreurs, idem pour les avertissements et infos */
$erreurs = array();
$avertissements = array();
$informations = array();

/* tableau des séparateurs */
$separateurs = array(
"v" => ",",
"ve" => ", ",
"eve" => " , ",
"vr" => ",<br />",
"ver" => ", <br />",
"pv" => ";",
"pve" => "; ",
"epve" => " ; ",
"pvr" => ";<br />",
"pver" => "; <br />",
"pipe" => "|",
"epipe" => " |",
"pipee" => "| ",
"epipee" => " | ",
"e" => " ",
"er" => " <br />",
"t" => " ",
"tr" => "\t<br />",
"r" => "<br />",
"nix" => "",
"nixr" => "<br />"
);


/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
/* ----- DEBUT DES FONCTIONS ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- --- */
/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
/* fonction pour récupérer les adresses
* elle vient du script "Extraire les adresses e-mail d'une chaine de caractères" par Hugo HAMON (<webmaster@apprendre-php.com>)
* http://www.apprendre-php.com/portions-de-script/script-20-extraire-les-adresses-e-mail-d-une-chaine-de-caracteres.html
*/
function extraireCourriels($texte, $suppDoublons = 1)
{
/* expra (expreg est une mauvaise traduction ^_^) qui définit une adresse de courriel */
$modeleDAdresse = "`\w(?:[-_.]?\w)*@\w(?:[-_.]?\w)*\.(?:[a-z]{2,6})`";

/* on récupère dans $texte tout ce qui est comme $modeleDAdresse et on le met dans le tableau $courriels */
if (false !== preg_match_all("$modeleDAdresse", $texte, $courriels))
{
/* si le tableau d'adresses dans $courriels a au moins un élément et que celui-ci est non vide */
if( is_array($courriels[0]) && count($courriels[0]) > 0 )
{
if ($suppDoublons)
{ /* on supprime les emails doublons parmi $courriels */
return array_unique($courriels[0]);
}
else
{
return $courriels[0];
}
}
} // FIN du if (false !== preg_match_all("$modeleDAdresse", $texte, $courriels))

return null;
} // FIN function extraireCourriels


/* fonction qui détecte les doublons dans un tableau, renvoie true si au moins un */
function contientDoublons($tableau)
{
$doublons = false; // valeur pas défaut
$freq = array_count_values($tableau); // frequence de chaque valeur du $tableau

foreach ($freq as $valeur)
{
if ($valeur != 1)
{
$doublons = true;
break;
}
}
return $doublons;
} // FIN function ilYADesDoulbons($tableau)


/* fonction pour ajouter le séparateur à la fin de chaque membre du tableau (via array_walk) */
function ajouterSeparateur(&$element, $cle, $separateur = "ve")
{
$element .= $separateur;
}


/* fonction qui classe les valeurs */
function trier($tableau, $critere = "app")
{
if ($critere == "app")
{
return $tableau;
}
elseif ($critere == "anti-app")
{
return $listeTriee = array_reverse($tableau);
}
elseif ($critere == "alpha")
{
asort($tableau);
return $tableau;
}
elseif ($critere == "anti-alpha")
{
arsort($tableau);
return $tableau;
}
elseif ($critere == "nat")
{
natsort($tableau);
return $tableau;
}
elseif ($critere == "anti-nat")
{
natsort($tableau);
return $listeTriee = array_reverse($tableau);;
}
} // FIN function trier


/* fonction qui met en forme le tableau et intègre le balisage */
function baliser($tableau, $conteneur = "1p")
{
if ($conteneur == "1p")
{
$listeAAfficher = "\n<p>";
$listeAAfficher .= implode("", $tableau); // transforme le array en string, sans séparateur ("")
$listeAAfficher .= "</p>\n";
return $listeAAfficher;
}
elseif ($conteneur == "xp")
{
foreach($tableau as $valeur)
{
$listeAAfficher .= "<p>$valeur</p>\n";
}
return $listeAAfficher;
}
elseif ($conteneur == "ul")
{
$listeAAfficher = "\n<ul>\n";
foreach($tableau as $valeur)
{
$listeAAfficher .= "<li>$valeur</li>\n";
}
$listeAAfficher .= "</ul>\n";
return $listeAAfficher;
}
elseif ($conteneur == "ol")
{
$listeAAfficher = "\n<ol>\n";
foreach($tableau as $valeur)
{
$listeAAfficher .= "<li>$valeur</li>\n";
}
$listeAAfficher .= "</ol>\n";
return $listeAAfficher;
}
elseif ($conteneur == "textarea")
{
if (count($tableau) == 1) {$nbr = "l'adresse";}
else {$nbr = "les adresses";}

$listeAAfficher = "\n<form action=\"\" method=\"post\" name=\"formresultat\">\n<p><textarea name=\"resultat\" rows=\"7\" cols=\"80\">";
$listeAAfficher .= implode("", $tableau); // transforme le array en string, sans séparateur ("")
$listeAAfficher .= "</textarea></p>\n</form>\n";
return $listeAAfficher;
}
} // FIN function baliser


/* fonction pour afficher les erreurs, avertissement et informations (qui contiennent du balisage) */
/* renvoit true si au moins une remarque */
function afficherRemarques($tableau, $type = "information")
{
if ($type != "erreur" && $type != "avertissement" && $type != "information")
{$type = "information";}

$nbr = count($tableau);
if ($nbr != 0) {$retour = true;} // il y a au moins une remarque à afficher
else {$retour = false;}

if ($nbr == 1)
{
echo "\n<div class=\"$type\">\n\t<p><strong>" .ucfirst($type). "</strong> :</p>\n\t$tableau[0]\n</div> <!-- FIN de la <div class=\"$type\"> -->\n";
}
elseif ($nbr > 1)
{
echo "\n<div class=\"$type\">\n\t<p><strong>" .ucfirst($type). "s ($nbr)</strong> :</p>\n<ol>\n";
foreach($tableau as $val)
{
echo "\t<li>$val</li>\n";
}
echo "</ol>\n</div> <!-- FIN de la <div class=\"$type\"> -->\n";
}

return $retour;
} // FIN function afficherRemarques($tableau, $type)


function verifRep($dossierVoulu)
{
/* ETAPE 1 : on détermine la liste des dossiers dans le répertoire courant */
$dossiers = array();
if ($repCourant = opendir('.'))
{
while ( false !== ($fichier = readdir($repCourant)) )
{
if ($fichier != "." && $fichier != "..")
{
$dossiers[] = $fichier;
}
}
closedir($repCourant);
}

/* ETAPE 2-A : si il N'y a PAS de répertoire $dossierVoulu dans celui courant, on le créé */
if (!in_array($dossierVoulu, $dossiers))
{
mkdir($dossierVoulu, '0777');
}

/* ETAPE 2-B : si il Y A un répertoire $dossierVoulu, on le vide */
if (in_array($dossierVoulu, $dossiers))
{
chdir($dossierVoulu); // on se déplace vers le dossier (on y entre)

/* on détermine la liste $fichiers des fichiers dans le répertoire $dossierVoulu */
$fichiers = array();
if ($dossierDeTravail = @opendir('.')) // /! il y a un warning à ce niveau-là, mais ça marche quand même apparemment
{
while ( false !== ($fichier = readdir($dossierDeTravail)) )
{
if ($fichier != "." && $fichier != "..")
{
$fichiers[] = $fichier;
}
}
// closedir($dossierDeTavail);
}
$nombreFichiers = count($fichiers);
// chmod($dossierVoulu", 0744); peut être requis pour la suppression des fichiers

/* on supprime tous les fichiers dans $dossierVoulu */
for ($i = 0; $i < $nombreFichiers; $i++)
{ /* on évite le dossier courant & celui parent (très important !) */
if ($fichiers[$i] != "." && $fichiers[$i] != ".." && !is_dir($fichiers[$i]))
{
unlink($fichiers[$i]); // supprime le fichier
}
}

chdir("../"); // retour au dossier parent (celui courant dan lequel on était à la base)
} // FIN ETAPE 2-B
return NULL;
} // FIN function verifRep($dossierVoulu) ; elle ne renvoit rien




/* fonction pour générer le fichier en .csv + créer le lien */
// fonction abandonnée car le dossier était accessible à n'importe quel internaute !
function exporterCSV($courriels, $nombreAdresses, $sep, $dossier)
{
verifRep($dossier);

$ip = str_replace(".", "-", $_SERVER['REMOTE_ADDR']);
$nom = 'courriels-extraits_' .date("dMy_H\hi\m\i\\ns\s_"). $ip . '.csv';
$chemin = "$dossier/$nom"; // chemin relatif du fichier à enregistrer

/* on ouvre le fichier et on va écrire */
$fichier = fopen($chemin, "w+"); // chaque suivant écrase le précédent

$contenu = "courriels\n"; // première ligne
$contenu .= implode($sep, $courriels); // une virgule (ou le ) sépare chaque entrée

// tmp pour confidentialite fwrite($fichier, $contenu);
// tmp pour confidentialite fclose($fichier); // on a fini de le générer

$poids = filesize($chemin);
$unite = "octets";
if ($poids >= 1048576)
{
$poids = round(($poids/1048576), 3);
$unite = "<abbr title=\"méga-octets\">Mo</abbr>";
}
elseif ($poids >= 1024)
{
$poids = round(($poids/1024), 3);
$unite = "<abbr title=\"kilo-octets\">Ko</abbr>";
}

$exportCSV = "\n<p id=\"exports\"><a href=\"$chemin\">T&eacute;l&eacute;charger $nombreAdresses au format CSV : <samp>$nom</samp> ($poids $unite)</a>.</p>\n";

/* temporaire, pour confidentialité */
$exportCSV = "Fonction désactivé pour quelques temps, désolé.";

return $exportCSV;
} // FIN unction exporterCSV($courriels, $leNombre)

/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
/* ----- FIN DES FONCTIONS ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */

/* si le formulaire a été envoyé */
if ($_POST)
{
/* on récupère le texte brut et les choix */
$texte = $_POST['texte'];
$conteneur = $_POST['conteneur'];
$separateur = $separateurs[$_POST['separateur']];
$critereTri = $_POST['tri'];
$suppDoublons = $_POST['suppdoublons'][0]; // car info envoyée par case à cocher
// tmp pour confidentialite $export = $_POST['export'][0];
// tmp pour confidentialite $sepcsv = $separateurs[$_POST['sepcsv']];

/* on donne à $doublons des valeurs (de type int) qui nous arrange */
if ($suppDoublons == "1") {$suppDoublons = 1;}
else {$suppDoublons = 0;}

/* l'utilisateur a-t'il bien saisi qqch ? on calcule la la longueur du texte après avoir supprimé les espaces */
if (strlen(trim($texte)) == 0)
{
$erreurs[] = "<p>Vous n'avez rien saisi dans la zone de texte ! <a href=\"#p_texte\">Retour &agrave la zone de saisie</a>.</p>";
}

/* ----- on va traiter le texte ----- */

/* on extrait les adresses et on en fait un tableau */
$courrielsBruts = extraireCourriels($texte, $suppDoublons);
$nombreCourriels = count($courrielsBruts); // (on a déja supprimé les doublons si c'était demandé)

/* y a-t-il tout de même des doublons ? */
if ($nombreCourriels > 0)
{
$ilYADesDoublons = contientDoublons($courrielsBruts);
if (!$suppDoublons && $ilYADesDoublons) // si l'utilisateur n'a pas demandé leur suppression et qu'il y en a tout de même
{
$avertissements[] = "<p>Il y a au moins un doublon parmi vos courriels. Nous vous conseillons de cocher l'option &quot;Supprimer les doublons&quot;. <a href=\"#p_doublons\">Retour &agrave; l'option &quot;Supprimer les doublons&quot;</a>.</p>";
}
}

/* on réagit en fonction du nombre d'adresses trouvé(e)(s) */
if ($nombreCourriels == 0)
{
$avertissements[] = "<p>Votre texte ne contient aucun courriel. <a href=\"#p_texte\">Retour &agrave la zone de saisie</a>.</p>";
}
elseif ($nombreCourriels == 1)
{
if($export == "csv")
{
$uneAdresse = "<p>Votre texte ne contient qu'une seule adresse de courriel. La voici. (<a href=\"#exports\">La t&eacute;l&eacute;charger</a>.)</p>";
}
else
{
$uneAdresse = "<p>Votre texte ne contient qu'une seule adresse de courriel. La voici.";
}
$informations[] = $uneAdresse;
}
if ($nombreCourriels >= 1)
{
$preListe = $courrielsBruts; // copie pour garder intact $courrielsBruts
array_walk($preListe, 'ajouterSeparateur', $separateur);

$listeTriee = trier($preListe, $critereTri);

$listeAAfficher = baliser($listeTriee, $conteneur);

if($export == "csv")
{
$avertissements[] = "<p>Votre fichier a &eacute;t&eacute; g&eacute;n&eacute;r&eacute;, mais il <em>ne sera pas sauvegard&eacute; sur le serveur</em>. Il sera &eacute;cras&eacute; lors de la prochaine extraction. Si vous le d&eacute;sirez, vous devez le t&eacute;l&eacute;charger <em>maintenant</em>.<p>";
}
}

/* ----- on a fini de traiter le texte ----- */

} // FIN du if ($_POST)
/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
/* ----- FIN du script (partie principale) ----- ----- ----- ----- ----- ----- ----- ----- - */
/* ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- */
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Extraire toutes les adresses e-mail d'un texte | Une alternative &agrave; <?php echo afficheUnDomaineTTM(); ?></title>
<style type="text/css">
body {
padding: 1ex;
max-width: 980px;
margin: 0 auto;
}
h1 {
text-align: center;
}
h1 span {
display: block;
font-size: .5em;
}
h2 {
padding-left: 20px;
}
h3 {
padding-left: 40px;
margin-bottom: 0;
}

#btn_raz {
border: none;
background: white;
font-size: .7em;
text-decoration: underline;
}
#btn_raz:focus, #btn_raz:hover {
background: #CCC;
}


.erreur { border-color: red; }
.avertissement { border-color: orange; }
.information { border-color: green; }
.erreur, .avertissement, .information { /* chaque dl */
margin: 10px 0; /* top+bottom et right+left */
border-width: 2px;
border-style: solid;
border-left-width: 15px;
padding: 0 10px 0; /* top, right+left, bottom */
background: white;
}
/* .erreur dt, .erreur dd, .avertissement dt, .avertissement dd, .information dt, .information dd {
margin: 1ex 0; /* marges verticales fusionnent */
padding: 0;
/* } */
/*.erreur p { border-left-color: red; }
.avertissement p { border-left-color: orange; }
.information > p { border-left-color: green; }
.erreur > p, .avertissement > p, .information > p {
border-left-width: 5px;
border-left-style: solid;
padding-left: 10px;
} */


#courriels {
padding: 1ex; padding-bottom: 0;
margin-bottom: 0;
border-bottom: 2px solid black;
}
#resultat {
background: #DDD;
padding: 1ex;
}

#a-propos {
border-top: 2px solid black;
margin: 1em 0;
}

img {
float: left;
margin: 0 1ex 1ex 0;
}

#pied {
clear: both;
margin: 0;
border-top: 2px solid black;
padding: 0 1ex;
text-align: right;
font-family: Georgia, Arial, "Trebuchet MS";
}
#pied p {
margin: 1ex 0;
}
strong.discret {
font-weight: normal;
}
</style>
<script type="text/javascript">
function raz()
{ /* le bouton reset */
document.getElementById('form').texte.value = "";
}
</script>
</head>

<body id="body">
<h1>Extracteur en-ligne d'adresses mail <span>une alternative gratuite et <a href="#licence">open-source*</a> &agrave; www.tictacmail.com</span></h1>

<?php

if(!isset($_SERVER['HTTPS']) ||
$_SERVER['SCRIPT_URI'] == "http://mathiaspoujolrost.net/outils/extraire-courriels.php" ||
$_SERVER['SCRIPT_URI'] == "http://www.mathiaspoujolrost.net/outils/extraire-courriels.php"){
echo "\n<div class=\"avertissement\">\n\t<p><strong>Avertissement</strong> :
</p>\n\t<p>Pour plus de confidentialité, <a href=\"https://mathiaspoujolrost.net/outils/extraire-courriels.php\">utilisez cette page dans sa forme s&eacute;curis&eacute;e (HTTPS implique le chiffrement)</a>. Votre Fournisseur d'Acc&egrave;s &agrave; Internet ne verra pas ce que vous y avez fait, et les adresses e-mail ne transiteront <strong>pas en clair</strong> sur le r&eacute;seau (tant avant que apr&egrave;s l'extraction). Toutefois, cette forme actuelle non s&eacute;curis&eacute;e (HTTP) fonctionne aussi bien.</p>\n\t<p>Note : ce site ne d&eacute;tenant pas encore de certifical S.S.L. ou T.L.S., votre navigateur (Firefox, Opera…) pourrait vous demander une exception de s&eacute;curit&eacute; relative à ce sous-domaine (vide).mathiaspoujolrost.net . Vous pourrez la r&eacute;voquer &agrave; tout instant.</p>\n</div>";
}
?>

<form action="#courriels" method="post" id="form">
<p>Ce formulaire vous permet de ne sélectionner <strong>que</strong> les adresses mail d'un texte.</p>

<p id="p_texte">Collez dans le zone ci-apr&egrave;s <label for="f_texte">votre texte brut contenant les adresses email &agrave; extraire</label> : <br /> <textarea id="f_texte" name="texte" rows="7" cols="80"><?php /* on rappelle le texte d'origine */ if ($_POST) {echo $texte;} ?></textarea></p>

<h2>Options</h2>
<p><a href="#soumettre">Passer directement à l'envoi du formulaire</a>.</p>

<fieldset>
<legend>Présentation des adresses</legend>
<p><label for="f_separateur">Separateur entre les courriels</label> : <select name="separateur" id="f_separateur">
<optgroup label="basé sur une virgule">
<option value="v">une virgule</option>
<option value="ve" selected="selected">une virgule et un espace (, )</option>
<option value="eve">un espace, une virgule et un espace ( , )</option>
<option value="vr">une virgule et un retour &agrave; la ligne</option>
<option value="ver">une virgule, un espace et un retour &agrave; la ligne</option>
</optgroup>
<optgroup label="basé sur un point-virgule">
<option value="pv">un point-virgule</option>
<option value="pve">un point-virgule et un espace (; )</option>
<option value="epve">un espace, un point-virgule et un espace ( ; )</option>
<option value="pvr">un point-virgule et un retour &agrave; la ligne</option>
<option value="pver">un point-virgule, un espace et un retour &agrave; la ligne</option>
</optgroup>
<optgroup label="basé sur une barre verticale (|)">
<option value="pipe">une barre verticale</option>
<option value="epipe">un espace, une barre verticale ( |)</option>
<option value="pipee">une barre verticale, un espace (| )</option>
<option value="epipee">un espace, une barre verticale, un espace ( | )</option>
</optgroup>
<optgroup label="basé sur un espace ou une tabulation">
<option value="e">un espace</option>
<option value="er">un espace et un retour &agrave; la ligne</option>
<option value="t">une tabulation</option>
<option value="tr">une tabulation et un retour &agrave; la ligne</option>
</optgroup>
<optgroup label="autres">
<option value="r">un retour &agrave; la ligne (&lt;br /&gt;)</option>
<option value="nix">rien du tout</option>
<option value="nixr">rien et un retour à la ligne</option>
</optgroup>
</select></p>

<p><label for="f_conteneur">Conteneur des courriels</label> : <select name="conteneur" id="f_conteneur">
<option value="1p" selected="selected">un seul paragraphe pour tous</option>
<option value="xp">un paragraphe par courriel</option>
<option value="ul">une liste &agrave; puce non num&eacute;rot&eacute;e (&lt;ul&gt;)</option>
<option value="ol">une liste à puce ordonn&eacute;e (&lt;ol&gt;)</option>
<option value="textarea">une zone de texte (&lt;textarea&gt;)</option>
</select></p>
</fieldset>

<fieldset>
<legend>Tri des adresses</legend>
<p><label for="f_tri">Crit&egrave;re et ordre de tri</label> : <select name="tri" id="f_tri">
<option value="app" selected="selected">ordre d'apparition</option>
<option value="anti-app">ordre inverse de celui d'apparition</option>
<option value="alpha">ordre alphab&eacute;tique</option>
<option value="anti-alpha">ordre inverse de celui alphab&eacute;tique</option>
<option value="nat">ordre naturel</option>
<option value="anti-nat">ordre inverse de celui naturel</option>
</select></p>
</fieldset>

<fieldset>
<legend>Autres options</legend>
<p id="p_doublons"><label for="f_doublons">Supprimer les doublons</label> <input type="checkbox" name="suppdoublons[]" value="1" checked="checked" id="f_doublons" /></p>

<!-- <p style="display:none"><label for="f_export_csv">Exporter les courriels dans un fichier <abbr xml:lang="en" title="comma separated values">CSV</abbr></label> <input type="checkbox" name="export[]" value="csv" checked="checked" id="f_export_csv" /> (<label for="f_sep_csv">s&eacute;parateur</label> : <select name="sepcsv" id="f_sep_csv">
<option value="v">une virgule</option>
<option value="ve">une virgule et un espace</option>
<option value="eve">un espace, une virgule et un espace</option>
<option value="pv">un point-virgule</option>
<option value="pve">un point-virgule et un espace</option>
<option value="epve">un espace, un point-virgule et un espace</option>
<option value="e">un espace</option>
<option value="t">une tabulation</option>
</select>)</p> -->
</fieldset>

<p id="soumettre"><input type="submit" value="Extraire les adresses de ce texte" /> <input type="reset" value="R&eacute;initialiser le formulaire" id="btn_raz" title="remise à zéro" onclick="raz();" /> <a href="#form">Retour au d&eacute;but du formulaire</a>.</p>
</form>

<?php
if ($_POST) // si le formulaire a été envoyé
{
echo "<h2 id=\"courriels\">Résultat de l'extraction</h2>";

$err = afficherRemarques($erreurs, "erreur");
if (!$err) // si il n'y a pas d'erreur
{
afficherRemarques($avertissements, "avertissement");
afficherRemarques($informations, "information");
}

/* on affiche les adresses si il y en a */
if ($nombreCourriels > 1)
{
if ($export == "csv")
{
echo "<p>Voici vos $nombreCourriels adresses (<a href=\"#exports\">les t&eacute;l&eacute;charger</a>) :</p>\n";
}
else
{
echo "<p>Voici vos $nombreCourriels adresses :</p>";
}
echo "<div id=\"resultat\">\n$listeAAfficher\n</div>";
if ($export == "csv")
{
echo $exportCSV = exporterCSV($courrielsBruts, "les adresses", $sepcsv, $dossierCSV);
}
}
elseif ($nombreCourriels == 1)
{
echo "<div id=\"resultat\">\n$listeAAfficher\n</div>";
if ($export == "csv")
{
echo $exportCSV = exporterCSV($courrielsBruts, "l'adresse", $sepcsv, $dossierCSV);
}
}
$cettepage = $_SERVER['PHP_SELF'];
echo "<p><a href=\"#form\">Modifier la saisie (retour au d&eacute;but du formulaire)</a>.</p>\n <p><a href=\"$cettepage\">Commencer une nouvelle extraction</a>.</p>";

} // FIN if ($_POST)
?>
<h2 id="a-propos">A propos</h2>

<h3 id="licence">* Licence</h3>
<p><img alt="Creative Commons Attribution Non-Commercial" src="https://i.creativecommons.org/l/by-nc/2.0/fr/88x31.png" /> <img alt="CC-GNU General Public Licence" src="https://creativecommons.org/images/public/cc-LGPL-a.png" /> Cet outil et <a href="?source">son code source (en PHP 4)</a> sont publi&eacute;s depuis le 2 d&eacute;cembre 2012 sous les licences <a rel="license" href="https://creativecommons.org/licenses/by-nc/2.0/fr/">Creative Commons : Attribution Non-Commercial</a> et <a href="https://creativecommons.org/licenses/LGPL/2.1/deed.fr">GNU : LGPL</a>.</p>

<div id="pied">
<p><a href="#body">Retour en haut</a>. Outil codé par <a href="https://monwiki.accessibilisation.net/pmwiki-2dot2dot36/pmwiki.php?n=Divers.PagesPubliques">Mathias Poujol-Rost</a> en décembre 2008 et janvier 2009.</p> <!-- http://www.phpsources.org/profil-poujolrost-mathias -->
<p>Mis à jour le 8 novembre 2011 pour motif de confidentialité (r&eacute;pertoire d'export du fichier .csv) et le 2 d&eacute;cembre 2012 pour sémantique des affichages d'erreurs + HTTPS.</p>
<p>Ce service est une <strong class="discret">alternative</strong> libre &agrave; <strong class="discret"><a href="http://ixquick.com/do/metasearch.pl?query=tictacmail.com&amp;cat=web&amp;pl=ff&amp;language=francais">www.tictacmail.com</a></strong>.</p>

</div>

</body>
</html>

mercredi 2 mai 2012

[traduction] Découvrez DuckDuckHack

Voici une adaptation du billet Introducing DuckDuckHack publié le 1er mai 2012 sur le blogue de Gabriel Weinberg, fondateur du moteur de recherche DuckDuckGo. La plupart des liens sont en anglais.

Je pense que la plupart des résultats de recherche pourrait bénéficier d'une certaine forme de réponse instantanée [la fonctionnalité « Zero-Click infobox » du moteur de recherche] (comme xkcd). DuckDuckGo propose de nombreux goodies, mais je pense que nous ne faisons que gratter la surface de ce qui peut y être réalisé.

C'est pourquoi nous annonçons aujourd'hui DuckDuckHack : une plateforme ouverte pour créer des extensions de réponse instantanée pour DuckDuckGo. Voyez-les comme des add-ons pour Firefox.

Il y a sans doute plus d'une recherche qui vous a frustré. Peut-être que certains de ces résultats auraient pu être amélioré par de superbes réponses instantanées. Partagez vos idées !

Par exemple, supposons que vos faites souvent des recherches sur la bioinformatique, les pièces de Lego ou d'autres sujets dont nous ne connaissons pas grand-chose. Vous êtes donc bien placé pour aider à créer de bonnes réponses instantanées dans ce domaine et améliorer vos propres résultats, ainsi que ceux des autres utilisateurs qui font des recherches similaires. Nous espérons que DuckDuckHack vous donnera l'opportunité de faire cela.

Allez lire ce tutoriel à DuckDuckHack.com qui répond aux questions de base quoi, pourquoi et comment. Vous pouvez surveillez l'arrivée de nouvelles extensions via Twitter et obtenir de l'aide sur la liste de diffusion or par tchat.

Il y a actuellement quatre types d'extension qui permettent une large gamme de réponses instantanées. Certains des interfaces de codage et de test, peu pratiques, sont en train d'être rapidement corrigées. En d'autres mots, c'est une Plateforme "Minimum Viable" :)

Évidemment, on adorerait recevoir vos avis au fur et à mesure que vous faisons évoluer le service ! Vous pouvez nous rejoindre sur la liste d'annonce pour recevoir les mises-à-jour les plus importantes.

Fin de la traduction. Lien vers l'article original (en anglais).

dimanche 8 avril 2012

L'EMT par Pôle Emploi, opportunité mal connue de « validation de formation » ?

Il y a plusieurs jours, j'avais un rendez-vous chez Pôle Emploi, que j'attendais depuis des mois.

Outre les objectifs prévisibles du RDV, on m'a présenté un dispositif parfois appelé « découverte métier » mais dont le vrai nom est Évaluation en Milieu de Travail (EMT). C'est une sorte de période finale de formation ou de validation des acquis, qui permet à un diplômé de mettre un pied en entreprise pour vérifier si ses connaissances et savoirs-faire sont raccord avec le besoins réels du métier visé.

Il est pris en charge par une titulaire en poste, qu'il assiste au quotidien et qui doit veiller à ce que le travail soit bien réalisé, correctement et dans les temps impartis. Le demandeur n'est pas rémunéré mais reste inscrit à PE et continue de percevoir ses indemnités ASSEDICs s'il en percevait avant. À la fin de l'évaluation (80 heures maximum soit deux semaines), l'employeur doit noter le demandeur, un peu comme à la fin d'un stage.

La mise en place d'une telle période se fait après signature d'une convention tripartite entre Pôle Emploi, le demandeur d'emploi et l'employeur-hôte. Ce dernier doit être assuré, affin de garantir la sécurité au demandeur d'emploi en cas d'accident durant le dispositif.

Il est évident qu'il ne faut pas en abuser... des deux côtés. Le demandeur ne peut pas faire 15 EMT à la suite, et la société ne peut user que de ce type de « contrat ». L'objectif pour PE et pour le demandeur est bien sûr que'il soit embauché après l'EMT. En tout cas, ce dispositif m'intéresse.

Voici la brochure reçue à ce rendez-vous (cliquez dessus pour la voir en grande taille) :

Présentation du dispositif sur le site de Pôle Emploi : http://www.pole-emploi.fr/candidat/l-evaluation-en-milieu-de-travail-emt--@/suarticle.jspz?id=5109 (côté candidat).

- page 1 de 2