Prado, SQLMap, TRepeater et TPager: requêtes SQL personnalisées avec pagination

En utilisant les classes métiers standards de Prado, je n’ai pas trouvé moyen d’exploiter correctement une relation de type “plusieurs à plusieurs” (many to many) avec la méthode “withXXXX($critere, $value)”. Mon problème était simple: la méthode “withXXXX()” utilise une sous-requête pour récupérer les éléments dépendants d’une relation à la place d’un “INNER JOIN”. Il m’est apparu impossible de récupérer seulement les éléments ayants une relation existante.

Pour illustrer ce cas, prenons mes 2 entités:

  • VideoRecord
  • CategorieRecord

Une vidéo peut être associée à plusieurs catégories, et une catégorie peut être associées à plusieurs vidéos. (many to many)
Si je désire récupérer toutes les vidéos appartenant à la catégorie avec l’id 2, je vais utiliser cette méthode:
VideoRecord::finder()->withCategories('id = ?', 2)->findAll()

Cette méthode va me retourner tous les objets vidéos, avec une valeur null sur la propriété category lorsque cette dernière ne correspond pas à l’id 2.

Afin de palier à cette problématique tout en optimisant mes requêtes SQL, j’ai découvert les SQLMap avec Prado, qui permettent de gérer des requêtes SQL entièrement personnalisées. L’unique difficulté réside dans la gestion de la pagination pour les requêtes stockées dans les SQLMaps en utilisant des contrôles de type TRepeater et TPager.

La marche à suivre ci-après résume la création des SQLMaps et l’adaptation d’un contrôle contenant un TRepeater et un TPager avec les entités décrites précédemment (VideoRecord et CategorieRecord).

  1. Dans le fichier protected/application.xml, ajouter entre <modules> et </modules>:
    <module id="sqlmap" class="System.Data.SqlMap.TSqlMapConfig" EnableCache="false"
    ConfigFile="Application.database.sqlmap" ConnectionID="dbVod" />
    (pensez à modifier la propriété ConnectionID en fonction de votre configuration)
  2. Créer un fichier protected/database/sqlmap.xml avec le contenu suivant:
    <?xml version="1.0" encoding="UTF-8" ?>
    <sqlMapConfig>
    <sqlMap resource="maps/VideoRecord.xml" />
    </sqlMapConfig>
  3. Créer un fichier protected/database/maps/VideoRecord.xml avec le contenu suivant:
    <sqlMapConfig>
    <select id="SelectVideosByCategoryAndStatus" resultClass="VideoRecord"
    parameterClass="SelectVideosByCategoryAndStatus_Param_Item">
    select     v.*
    from     video as v
    inner join categorie_video as c on v.id = c.id_video
    where     c.id_categorie = #idCategorie#
    and        v.id_status = #idStatus#
    order by #orderBy# #order#
    </select>
    <select id="SelectVideosByCategoryAndStatus_Pager" resultClass="VideoRecord"
    parameterClass="SelectVideosByCategoryAndStatus_Param_Item">
    select     v.*
    from     video as v
    inner join categorie_video as c on v.id = c.id_video
    where     c.id_categorie = #idCategorie#
    and        v.id_status = #idStatus#
    order by #orderBy# #order#
    limit     #limit# offset #offset#
    </select>
    <select id="SelectVideosByCategoryAndStatus_Counter" resultClass="int"
    parameterClass="SelectVideosByCategoryAndStatus_Param_Item">
    select     count(v.id)
    from     video as v
    inner join categorie_video as c on v.id = c.id_video
    where     c.id_categorie = #idCategorie#
    and        v.id_status = #idStatus#
    </select>
    </sqlMapConfig>

    Notes: 3 requêtes différentes sont utilisées, 1 pour récupérer tous les résultats, 1 pour récupérer une “page” de résultats et 1 pour déterminer le nb. total de résultats.
  4. Editer le fichier protected/database/VideoRecord.php avec le contenu suivant:
    (Note: la classe SelectVideosByCategoryAndStatus_Param_Item représente les paramètres passés à la requête SQL. ATTENTION: si cette dernière n’est pas reconnue, il est nécessaire de la déclarer directement dans le contrôle qui l’utilise (par exemple au début du fichier /pages/controls/CategoriesListVideo.php).)

    
    
    <?php
    class VideoRecord extends TActiveRecord
    {
    	const TABLE=‘video’;
    
    	public $id;
    	public $title;
    	public $description;
    	public $date_added;
    	public $duration_sec;
    	public $views;
    	public $id_publisher;
    	public $id_status;
    
    	public $status;
    	public $publisher;
    	public $files=array(); 
    	public $categories=array(); 
    	public $tags=array();
    
    	public $videos=array();
    
    	public static $RELATIONS=array
        (
    		’status’ => array(self::BELONGS_TO‘VideoStatusRecord’),
    		‘publisher’ => array(self::BELONGS_TO‘UserRecord’),
    		‘files’ => array(self::HAS_MANY‘VideoFileRecord’‘id_video’),
            ‘categories’ => array(self::MANY_TO_MANY‘CategorieRecord’‘categorie_video’),
    		‘tags’ => array(self::MANY_TO_MANY‘TagRecord’‘tag_video’)
        );
    
    	public static function finder($className=__CLASS__)
    	{
    		return parent::finder($className);
    	}
    }
    
    /* sqlMap classes, see ./maps/VideoRecord.xml */
    class SelectVideosByCategoryAndStatus_Param_Item
    {
    	public $idCategorie;
    	public $idStatus;
    
    	public $orderBy ‘views’;
    	public $order ‘asc’;
    	public $offset 0;
    	public $limit 0;
    }
    ?>
  5. Le modèle du contrôle dans le fichier /pages/controls/CategoriesListVideo.tpl contient:
    <ul class="videoList">
    <com:TRepeater ID="rpVideos"
    ItemRenderer="Application.pages.videos.CategoriesListVideoRenderer"
    AllowPaging="true"
    AllowCustomPaging="true"
    />
    </ul>
    <com:TPager ControlToPaginate="rpVideos" OnPageIndexChanged="pageChanged" />
  6. Le code behind du contrôle dans le fichier /pages/controls/CategoriesListVideo.php contient:
    (Note: c’est dans ce contrôle que la gestion de la pagination est implémentée.)

    
    <?php
    class CategoriesListVideo extends TTemplateControl {
    	protected $ID_Category 0;
    
    	protected $sqlmap;
    	protected $sqlmap_param;
    	protected $PageSize 30;
    	protected $NbVideos 0;
    
    	public function onInit($param)
        {
            parent::onInit($param);
    	
    		$this->ID_Category = (int)$this->Request[‘id’];
    	
    		$this->sqlmap $this->Application->Modules[’sqlmap’]->Client;
    		$this->sqlmap_param = new SelectVideosByCategoryAndStatus_Param_Item;
    		$this->sqlmap_param->idCategorie $this->ID_Category;
    		$this->sqlmap_param->idStatus 2;
    	
    		$this->NbVideos $this->sqlmap->queryForObject(“SelectVideosByCategoryAndStatus_Counter”$this->sqlmap_param);
    		
    		$this->rpVideos->PageSize=$this->PageSize;
    		$this->rpVideos->VirtualItemCount $this->NbVideos;
     	
    		$this->populateData();
        }
    
    	public function pageChanged($sender,$param)
    	{
    		$this->rpVideos->CurrentPageIndex=$param->NewPageIndex;
    		$this->populateData();
    	}
    
    	protected function populateData()
    	{
    		$offset=$this->rpVideos->CurrentPageIndex*$this->rpVideos->PageSize;
    		$limit=$this->rpVideos->PageSize;
    		if($offset+$limit $this->rpVideos->VirtualItemCount)
    			$limit=$this->rpVideos->VirtualItemCount-$offset;
    		$this->rpVideos->DataSource=$this->getVideos($offset,$limit);
    		$this->rpVideos->DataBind();
    	}
    
    	protected function getVideos($offset$limit)
    	{	
    		$this->sqlmap_param->limit=$limit;
    		$this->sqlmap_param->offset=$offset;
    	
    		if (($offset 0) && ($limit 0))
    		{
    			$query_name ‘SelectVideosByCategoryAndStatus_Pager’;
    		
    		}
    		else
    		{
    			$query_name ‘SelectVideosByCategoryAndStatus’;
    		}
    	
    		return $this->sqlmap->queryForList($query_name$this->sqlmap_param);
    	}
    }
    ?>
    

Basé sur ce même modèle, il est possible d’adapter toutes requêtes SQL à un contrôle de type TRepeater.

Source (EN): http://www.pradosoft.com/forum/index.php?topic=12784

  • Share/Save/Bookmark

DomainKeys Identified Mail (DKIM) - Plesk, Qmail, SpamAssassin & DNS

Note: cette installation s’est déroulée sous Plesk 9.2 (CentOS 5.2) / SpamAssassin 3.2.5

L’implémentation de la norme DKIM au sein de Plesk est réalisable directement via l’interface d’administration. Cependant, dans le but d’en optimiser le fonctionnement, plusieurs éléments nécessitent une configuration appropriée.

Signature des messages sortants

  1. Activer DKIM sous Plesk
    Dans la page d’accueil de l’administrateur du serveur, dans le panneau “Serveur”, cliquer sur l’icône intitulé “Paramètres du serveur de messagerie”. Ensuite, sous la section “Protection anti-spam DomainKeys”, cocher les cases “Autoriser la signature des e-mails sortants” et “Vérifier les e-mails entrants”. Sauvegarder ces modifications en cliquant sur le bouton “OK”.
    (v. manuel Parallels Plesk)
    Attention: par le biais de cette méthode, la signature des messages sortants est activée pour TOUS les domaines! Etant donné que chacun d’eux nécessite une configuration DNS spécifique, il est recommandé de désactiver par la suite cette option pour tous les domaines (tjs. dans l’interface Plesk: section “Domaines”, cocher tous les domaines, et cliquer sur “modifier”,  puis sélectionner “Désactiver” au niveau de “Utiliser le système de protection anti-spam DomainKeys pour signer les e-mails sortants”), et de la ré-activer au cas par cas.
  2. Activer DKIM sous un domaine précis
    Sélectionner un domaine, puis aller sous “Comptes de messagerie” > “Paramètres du messagerie”.
    Cocher la case “Utiliser le système de protection anti-spam DomainKeys pour signer les e-mails sortants” et cliquer sur le bouton “OK”.
  3. Récupérer la clé publique pour l’enregistrement DNS
    A niveau du domaine, se rendre dans “Paramètres DNS”. Cliquer sur “Activer le service DNS” (si inactif).
    Une ligne intitulée “default._domainkey.DOMAINE.TLD” de type TXT est désormais présente.
    Copier sa valeur (”p=MHwwD…RclQIDAQAB;”) dans un fichier texte.
  4. Configurer le serveur DNS (indépendant de Plesk)
    Dans la zone du domaine concerné:
    - Ajouter une entrée TXT nommée “_domainkey” avec comme valeur “o=~” (ceci est moins restrictif que la règle par défaut de Plesk, à savoir qu’elle veut signifier que “presque” tous les messages sortants sont signés).
    - Ajouter une entrée TXT nommée “default._domainkey.DOMAINE.TLD” avec comme valeur l’élément copié précédemment au point 3 dans un fichier texte (”p=MHwwD…RclQIDAQAB;”).
    Enregistrer la zone.
    Attention: ce point n’est utile que si votre serveur DNS n’est pas alimenté par Plesk (serveur DNS maître indépendant)
  5. Test: Envoyer un email de votre domaine à un compte Yahoo ou GMail
    Dans l’en-tête du message, une ligne “DomainKey-Signature:” est présente, ainsi qu’une ligne “DomainKey-Status: good”.
    Si ce n’est pas le cas, contrôlé que la propagation des zones DNS s’est déroulée correctement après les modification au pt. 4.

Traitement des messages entrants

  1. Installer SpamAssassin via le repository d’ART
    Une fois le repository ART ajouté à Yum, exécuter la commande
    yum install spamassassin
    ou
    yum update spamassassin
  2. Mettre à jour les règles de SpamAssassin
    Exécuter les commandes
    sa-update
    service spamassassin restart
    service psa-spamassassin restart
  3. Installer les modules Perl Mail-DomainKeys et Mail-DKIM via le repository DAG
    Une fois le repository DAG ajouté à Yum, exécuter les commandes
    yum install perl-Mail-DomainKeys
    yum install perl-Mail-DKIM
  4. Editer les fichiers de configuration de SpamAssassin
    Fichier /etc/mail/spamassassin/v312.pre: décommenter (= enlever le # au début) la ligne:
    loadplugin Mail::SpamAssassin::Plugin::DKIM
    Fichier /etc/mail/spamassassin/local.cf: ajouter la ligne:
    score DKIM_VERIFIED -1.00
  5. Rédémarrer SpamAssassin
    service spamassassin restart
    service psa-spamassassin restart
  6. Tester: Envoyer un email vers votre domaine depuis un compte Yahoo ou GMail
    Au niveau de la ligne “X-Spam-Status”, les mots-clés “DKIM_SIGNED” et “DKIM_VERIFIED” sont présents.
    Le X-Spam-Level est inférieur si le mot clé “DKIM VERIFIED” est présent.

Notes:

  • Share/Save/Bookmark

Apache video streaming: flv et mp4 (H264) via modules open-source

Note: cette installation s’est déroulée avec Apache 2.2.3  (Plesk 9.2) sous CentOS 5.2

Pour réaliser du pseudo streaming via HTTP avec le serveur web Apache, il suffit d’installer deux modules open-source:

L’installation…

  1. Installer APXS pour Apache
    yum install httpd-devel
  2. Télécharger la source du module mod_flv
    wget http://people.apache.org/%7Epquerna/modules/mod_flvx.c
  3. Compiler et installer mod_flv
    apxs -c -i ./mod_flvx.c
  4. Créer/Editer un fichier de configuration mod_flv pour Apache
    vi /etc/httpd/conf.d/mod_flvx.conf
    avec le contenu suivant:
    LoadModule flvx_module modules/mod_flvx.so
    AddHandler flv-stream .flv
  5. Redémarrer Apache pour être certain que l’installation de mod_flv s’est bien déroulée
    service httpd restart
  6. Télécharger et décompresser le module H264 Streaming
    wget http://h264.code-shop.com/download/apache_mod_h264_streaming-2.2.5.tar.gz
    tar -xvzf apache_mod_h264_streaming-2.2.5.tar.gz
  7. Compiler et installer le module H264 Streaming
    cd ./mod_h264_streaming-2.2.5
    ./configure
    make
    make install
  8. Créer/Editer un fichier de configuration mod_flv pour Apache
    vi /etc/httpd/conf.d/mod_h264_streaming.conf
    avec le contenu suivant:
    LoadModule flvx_module modules/mod_flvx.so
    AddHandler flv-stream .flv
  9. Redémarrer Apache
    service httpd restart

Des fichiers flv avec des keyframes…

  • les clés peuvent être ajoutées sur un fichier flv existant en utilisant flvtool2 (DAG repository):
    flvtool2 -U video.flv

Tester le streaming HTTP…

Sources:

  • Share/Save/Bookmark

Définir le timeout d’un callback sous Prado (AJAX)

Par défaut, le timeout d’un callback sous Prado est de 30 secondes.
Il peut être définis indépendamment pour chaque contrôle de type TActiveButton (AJAX).

Pour se faire, il suffit d’éditer le fichier .page qui contient le bouton concerné.

Avant la modification, le contrôle du bouton est décrit ainsi:

<com:TActiveButton text=”Bouton AJAX” oncallback=”CallbackAction”>
</com:TActiveButton>

Il suffit d’y ajouter la proriété activecontrol.callbackoptions:

<com:TActiveButton text=”Bouton AJAX” oncallback=”CallbackAction” activecontrol.callbackoptions=”CallBackOptions”>
</com:TActiveButton>

Et de décrire les options de CallBack dans la page (après la déclaration du bouton):

<com:TCallbackOptions id=”CallBackOptions”>
	<prop:clientside.requesttimeout>60000</prop:clientside.requesttimeout>
</com:TCallbackOptions>

Dans l’exemple ci-dessus, la valeur 60′000 est en milli-secondes et représente 60 secondes.

Source:  Setting an AJAX timeout longer than 30 seconds in Prado

  • Share/Save/Bookmark

Magento - Augmenter la compatibilité des mails générés (newsletter, confirmation de commande, etc…)

Lorsque Magento envois des mails HTML, que ce soit pour la newsletter ou les différentes notifications, le format généré n’est pas compatible avec tous les navigateurs. Il arrive que le mail soit définis comme du SPAM (HTML_MIME_NO_HTML_TAG), ou soit carrément illisible dans le client mail (affichage du code HTML, plutôt que du message formaté). Cependant, il est possible de remédier simplement à ce problème en éditant deux fichiers php du CORE de Magento.

Les 2 fichiers Template.php à éditer se trouvent ci-après (relativement au dossier racine de l’installation de Magento):

  • ./app/code/core/Mage/Core/Model/Email/Template.php
  • ./app/code/core/Mage/Newsletter/Model/Template.php

Pour le premier, soit ./app/code/core/Mage/Core/Model/Email/Template.php, il faut éditer la fonction send() (ligne 345).
Remplacer le code ci-après:

if($this->isPlain()) {
$mail->setBodyText($text);
} else {
$mail->setBodyHTML($text);
}

par celui-ci:

 if($this->isPlain()) {
$mail->setBodyText($text);
} else {
$mail->setBodyText($text);
$mail->setBodyHTML($text);
} 

Pour le deuxième fichier, soit ./app/code/core/Mage/Newsletter/Model/Template.php, il faut faire la même modification (ligne 222).

Remplacer le code ci-après:

if($this->isPlain()) {
$mail->setBodyText($text);
} else {
$mail->setBodyHTML($text);
}

par celui-ci:

if($this->isPlain()) {
$mail->setBodyText($text);
} else {
$mail->setBodyText($text);
$mail->setBodyHTML($text);
}

Note: les N° lignes des fichiers Template.php mentionnés correspondent à la version 1.2.0.1 de Magento.

Sources et informations:

  • Share/Save/Bookmark

Anti-virus ClamAV, Greylisting et Postfix (Plesk 9.0.1 sur CentOS5)

Plesk 9 offre désormais la possibilité d’exploiter Postfix en remplacement de qmail. ClamAV, l’alternative gratuite à Dr. Web, est toujours exploitatble, et pour limiter le SPAM, Postgrey s’occupe du greylisting. La marche à suivre suivante permet d’installer ClamAV et Postgrey sur une installation Plesk 9 et Postfix. Elle est prévue pour CentOS 5.2, mais devrait sans autre fonctionner sur d’autres distributions.

- Plesk: Remplacer qmail par Postfix
Afin d’installer Postfix, il suffit d’exécuter l’AutoInstaller en ligne de commande et de sélectionner Postfix.
/usr/local/psa/bin/autoinstaller

- Configurer YUM pour utiliser les packages de Atomic Rocket Turtle (repository)
wget -q -O - http://www.atomicorp.com/installers/atomic.sh | sh

- Configurer YUM pour utiliser les packages de DAG (repository)
rpm -Uhv http://apt.sw.be/redhat/el5/en/i386/rpmforge/RPMS/rpmforge-release-0.3.6-1.el5.rf.i386.rpm

- Désinstaller DrWeb
rpm -qa | grep "drweb" | xargs rpm -e

- Installer ClamAV
yum install clamav clamd

- Installer ClamSMTP
Télécharger la dernière version sur http://www.inet.lt/clamsmtp/.
Note: la path /usr/src/redhat/RPMS/i386 peut varier en fonction de votre distribution.
rpm -ivh http://www.inet.lt/clamsmtp/clamsmtp-1.10-1.src.rpm
cd /usr/src/redhat/RPMS/i386
rpmbuild -bb clamsmtp.spec
rpm -ivh clamsmtp-1.10-1.i386.rpm

- Configurer Postfix
postconf -e "content_filter = scan:[127.0.0.1]:5025"
vi /etc/postfix/master.cf
Ajouter les lignes suivantes dans le fichier master.cf:

# AV scan filter (used by content_filter)
scan unix - - n - 16 smtp
        -o smtp_send_xforward_command=yes
        -o smtp_enforce_tls=no
# For injecting mail back into postfix from the filter
127.0.0.1:5026 inet n - n - 16 smtpd
        -o content_filter=
        -o receive_override_options=no_unknown_recipient_checks,no_header_body_checks
        -o smtpd_helo_restrictions=
        -o smtpd_client_restrictions=
        -o smtpd_sender_restrictions=
        -o smtpd_recipient_restrictions=permit_mynetworks,reject
        -o mynetworks_style=host
        -o smtpd_authorized_xforward_hosts=127.0.0.0/8

vi /etc/postfix/main.cf
Modifier la ligne “smtpd_recipient_restrictions” comme ci-dessous:

smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, check_policy_service inet:127.0.0.1:60000, reject_unauth_destination

Modifier la ligne “smtpd_client_restrictions” comme ci-dessous (pour faire fonctionner le SMTP AUTH):

smtpd_recipient_restrictions = permit_sasl_authenticated, reject_rbl_client bl.spamcop.net, reject_rbl_client cbl.abuseat.org, reject_rbl_client zen.spamhaus.org

Note: le fichier /etc/postfix/main.cf doit être modifié après chaque changement apporté à la configuration du serveur de mail depuis Plesk. Concernant la ligne “smtpd_recipient_restrictions”, il faut simplement s’assurer que le “permit_sasl_authenticated” viens en première position

- Configurer ClamSMTP
vi /etc/clamsmtpd.conf
Modifier les lignes suivantes:

OutAddress: 5026
Listen: 0.0.0.0:5025
ClamAddress: /tmp/clamd.socket
Action: drop
User: clamav

Note: la socket (ligne “ClamAdress:”) doit correspondre au contenu de /etc/clamd.conf

- Installer PostGrey
yum install postgrey

- Configurer PostGrey
vi /etc/rc.d/init.d/postgrey
Modifier la ligne “OPTIONS=”–unix=$SOCKET” comme ci-après:

OPTIONS="--pidfile=/var/run/postgrey.pid --unix=$SOCKET --inet=127.0.0.1:60000 --delay=29"

- Mettre à jour ClamAV
/usr/bin/freshclam
Créer une tâche planifiée (via interface Plesk, pour l’utilisateur root) exécutée chaque jour pour la commande:
/usr/bin/freshclam >/dev/null

- Lancer ClamD, ClamSMTP et Postgrey
/etc/rc.d/init.d/clamd start
/etc/rc.d/init.d/clamsmtpd start
/etc/rc.d/init.d/postgrey start

- Redémarrer Postfix
/etc/rc.d/init.d/postfix restart

- Contrôler le fonctionnement
Tout se trouve dans le fichier maillog…

- Surveiller les processus ClamD, ClamSMTPD et Postgrey
Si l’un des démons de ClamAV ou Postgrey venait à s’arrêter, les mails seraient bloqués dans la file d’attente de Postfix.
Il est recommandé de les surveiller avec PSMON.
yum install psmon
vi /etc/psmon.conf
Editer la configuration de psmon afin de commenter les 2 lignes “Disabled”. Et insérer les lignes suivantes:

<Process clamd>
        spawncmd        /sbin/service clamd start
        pidfile         /var/run/clamav/clamd.pid
</Process>

<Process clamsmtpd>
        spawncmd        /sbin/service clamsmtpd start
        pidfile         /var/run/clamav/clamsmtpd.pid
</Process>

<Process postgrey>
        spawncmd        /sbin/service postgrey start
        pidfile         /var/run/clamav/postgrey.pid
</Process>

Différentes sources:
Plesk9 integration with Postfix and ClamAV
Greylisting in Plesk 9.0
Postgrey selective greylisting and policyd-weight on Fedora
Plesk / Postfix / SPF / DNSRBL
Pour le bug “postfix-queue exit status 255″ (ça n’a pas fonctionné pour mon cas):
[HOTFIX] Postfix cannot send e-mails with attachments
Pour obtenir un rapport journalier de l’exploitation de Postfix:
Pflogsumm - The Postfix Log Entry Summarizer

  • Share/Save/Bookmark

Openquery “OLE DB ‘SQLOLEDB’ n’a pas réussi à démarrer de transaction distribuée”

L’erreur “OLE DB ‘SQLOLEDB’ n’a pas réussi à démarrer de transaction distribuée” ([OLE/DB Provider ‘SQLOLEDB’ ITransactionJoin::JoinTransaction returned 0×8004d00a]) retournée par un Openquery peut être résolue simplement.

Il suffit d’ajouter SET IMPLICIT_TRANSACTIONS OFF; avant l’exécution d’une requête ou d’une procédure stockée.
Avant (erreur):
select * from OPENQUERY(LOCALHOST, ‘exec mySP @Param = 123′)
Après (corrigé):
select * from OPENQUERY(LOCALHOST, ‘SET IMPLICIT_TRANSACTIONS OFF; exec mySP @Param = 123′)

  • Share/Save/Bookmark

Créer un script PHP exécutable en ligne de commande

Le langage PHP peut être utilisé pour scripter des fichiers exécutables en ligne de commande, au même titre que PERL (ou autres…). Ce mode de fonctionnement est pratique pour outrepasser les limites imposées par l’environnement d’Apache (sécurité, temps d’exécution, etc.).

Avant d’écrire du code, il est nécessaire de définir l’emplacement de l’interpréteur PHP (à noter que PHP est déjà installé sur votre machine). Pour se faire, il suffit d’exécuter la commande suivante (sous Linux): whereis php. Dans la majorité des cas, le résultat devrait contenir soit /usr/bin/php, soit /usr/local/bin/php. La première ligne du script devra tjs. reprendre l’emplacement de php, comme ci-après:
#!/usr/bin/php
Ensuite, vous pouvez écrire en PHP habituel, sans omettre les <?php ?> en début et fin de script.
Ci-après, un exemple de script qui affiche “Hello World” au prompt:
#!/usr/bin/php
<?php
echo "Hello World\n";
?>

Pour tester ce script (nommé ici test.php), il suffit de le rendre exécutable et de l’appeler comme une commande:
chmod 755 test.php
./test.php

Comment récupérer des arguments passer en ligne de commande?

Etant donné que le script PHP est désormais exécuté hors de l’environnement Apache, les arguments en ligne de commande sont la seule méthode qui permet de lui passer des paramètres (les variables POST/QueryString n’existent plus, tout comme les constantes d’environnement $SERVER). La variable (tableau) $argv permet de récupérer ces valeurs.
Ci-après, un exemple de script qui affiche “Hello World” suivi des arguments passés en ligne de commande:
#!/usr/bin/php
<?php
echo "Hello World $argv[0] $argv[1] $argv[2]\n";
?>

Le script est appelé ainsi (2 paramètres dans notre cas, l’index 0 retourne le nom du script): ./test.php Param1 Param2
Résultat: Hello World ./test.php Param1 Param2
A noter que $argv n’est pas limité à 2 paramètres, voir la doc de PHP à ce sujet.

Comment appeler un autre script (ou commande)?

Deux fonctions PHP existent pour exécuter un autre script ou commande:

  • passthru() : exécute et affiche le résultat brut
  • exec(): exécute sans afficher le résultat
  • Share/Save/Bookmark

SpamAssassin - Supprimer les SPAM automatiquement

SpamAssassin définit un score de SPAM pour chaque mail entrant. Si l’on désire, par exemple, supprimer tout les mails dépassant le seuil de 10, il suffit de configurer Qmail-Scanner…

Marche à suivre (Plesk 8.1, FC5, Qmail-Scanner et SpamAssassin via Atomic Rocket Turtle)

  1. Arrêter le service SpamAssassin: service spamassassin stop
  2. Editer le fichier /etc/qmail-scanner.ini: vi /etc/qmail-scanner.ini
    Modifier la ligne indiquant SA-DELETE="0" à SA-DELETE="5" (pour supprimer les mails avec un score >= 10)
    Sauvegarder le fichier et quitter vi.
  3. Reconfigurer Qmail-Scanner: /usr/bin/qmail-scanner-reconfigure
  4. Démarrer le service SpamAssassin: service spamassassin start

Désormais, plus aucun mail ayant un score de SPAM supérieur ou égal à 10 ne devrait passé.

ATTENTION: si les messages ne sont tjs. pas supprimer après cette marche à suivre, il est nécessaire de supprimer PSA-SpamAssassin selon la marche à suivre suivante…

  1. Supprimer psa-spamassassin: yum remove psa-spamassassin
  2. Fermer les instances de spamd: killall -9 spamd
  3. Définir le droit d’exécution sur SpamAssassin: chmod +x /etc/init.d/spamassassin
  4. Démarrer SpamAssassin: /etc/init.d/spamassassin start
  5. Reconfigurer Qmail-Scanner: qmail-scanner-reconfigure
  6. Editer /etc/sysconfig/spamassassin : vi /etc/sysconfig/spamassassin
    Modifier la ligne SPAMDOPTIONS="-d -c -m5 -H" en SPAMDOPTIONS="-d -c -m5 -H -u qscand"

Note: les messages effacés sont notifiés dans le maillog (/usr/local/psa/var/log/maillog) par qmail-scanner[*]: SA:SPAM-DELETED

  • Share/Save/Bookmark

Calculer un masque de sous-réseau à partir d’un range d’adresses IPs

Une fonction en T-SQL retournant le masque de sous-réseau (netmask) à partir de la première et dernière IP du range… Compatible MS SQL Server 2000.

Ci-dessous le code de la fonction calculant le masque:


create function getSubnetMask (@RangeIPStart as varchar(50), @RangeIPStop as varchar(50))
returns varchar(50)

as
-- Procedure Name : getSubnetMask
-- Created On : 22.01.2008
-- Dependencies: user-defined function SplitWords
begin
declare @Value as int
declare @SubnetMask as varchar(50)

set @SubnetMask = ''

DECLARE SubnetMask CURSOR FAST_FORWARD FOR
SELECT CASE WHEN (CONVERT(INT,IP1.[value]) = CONVERT(INT,IP2.[value]))
THEN 255
ELSE 255 - ((CONVERT(INT,IP1.[value]) ^ CONVERT(INT,IP2.[value])))
END AS value
FROM (SELECT * FROM [dbo].[SplitWords] (@RangeIPStart)) AS IP1
INNER JOIN (SELECT * FROM [dbo].[SplitWords] (@RangeIPStop)) AS IP2 ON IP1.pos = IP2.pos

OPEN SubnetMask
FETCH NEXT FROM SubnetMask INTO @Value
WHILE @@FETCH_STATUS = 0
BEGIN
if @SubnetMask <> ''
begin
set @SubnetMask = @SubnetMask+'.'
end

set @SubnetMask = @SubnetMask+CAST(@Value as varchar)

FETCH NEXT FROM SubnetMask INTO @Value
END
CLOSE SubnetMask
DEALLOCATE SubnetMask

return @SubnetMask
end


Cette dernière est dépendante de la fonction user-defined SplitWords… Le code:


CREATE FUNCTION [dbo].[SplitWords](@text varchar(8000))
RETURNS @words TABLE (pos smallint primary key, value varchar(8000))
AS
BEGIN
DECLARE @pos smallint,
@i smallint,
@j smallint,
@count smallint,
@s varchar(8000)

SET @pos = 1
SET @count = 0
WHILE @pos <= LEN(@text)
BEGIN
SET @i = CHARINDEX(' ', @text, @pos)
SET @j = CHARINDEX('.', @text, @pos)

IF @i > 0 OR @j > 0
BEGIN
IF @i = 0 OR (@j > 0 AND @j < @i)
SET @i = @j

IF @i > @pos
BEGIN
-- @i now holds the earliest delimiter in the string
SET @s = SUBSTRING(@text, @pos, @i - @pos)

INSERT INTO @words
VALUES (@count, @s)
SET @count = @count + 1
END

SET @pos = @i + 1
WHILE @pos < LEN(@text) AND SUBSTRING(@text, @pos, 1) IN (' ', ',')
SET @pos = @pos + 1
END
ELSE
BEGIN
INSERT INTO @words
VALUES (@count, SUBSTRING(@text, @pos, LEN(@text) - @pos + 1))

SET @pos = LEN(@text) + 1
END
END

RETURN
END


  • Share/Save/Bookmark