mp3 streaming via Apache et mod_flv

Le streaming de mp3 peut être réalisé en utilisant une application dédiée comme Icecast. Cependant, l’installation d’une telle application peut s’avérer contraignante sur un serveur web exploitant Apache.

Alors pourquoi ne pas utiliser directement Apache comme serveur de streaming?

Cette option est viable à deux conditions:

  • se contenter d’un pseudo-streaming
    gestion du timeshifting, soit possibilité d’écouter la fin d’un mp3 sans en avoir téléchargé le conten, mais aucune gestion de la bande passante
  • utiliser des fichiers flv
    les mp3s devront être intégrés à un fichier flv (Adboe Flash Video Codec, ce qui peut allourdir le fichier audio d’environ 10%

Premièrement, il est nécessaire d’installer le module mod_flv pour Apache. La démarche d’installation est décrite dans un précédent article: Apache video streaming: flv et mp4 (H264) via modules open-source.

Une fois ce module fonctionnel, il est nécessaire d’installer les logiciels ffmpeg (encodage de vidéos) et yamdi (injection de metadata dans le fichiers flv). L’installation sous CentOS 5.2 avec Plesk se déroule selon les étapes suivantes :

  1. Configurer yum pour utiliser le repository DAG
  2. Exécuter la commande :
    yum install ffmpeg
  3. Télécharger les dernières sources de yamdi sur le site de yamdi (sourceforge) :
    wget http://......../yamdi-1.6.tar.gz
  4. Décompresser et compiler yamdi :
    tar xzf yamdi-1.6.tar.gz
    
    cd yamdi-1.6
    
    gcc yamdi.c -o yamdi -O2 -Wall

Tous les outils nécessaire sont désormais installés.

L’étape suivante consiste à intégrer le fichier audio mp3 d’origine à un fichier flv ne présentant qu’une image noire comme contenu vidéo. ffmpeg est utilisé pour l’encodage et l’intégration du fichier source, et yamdi pour la création de keyframes afin de permettre le pseudo-streaming sur le fichier de sortie au format flv.

Afin de se simplifier la vie, il est recommandé de créer un script shell réalisant ce travail, comme décrit dans la marche à suivre suivante :

  1. Créer le script shell :
    vi mp3toflv.sh
  2. Contenu du script (en téléchargement ici) :
    #!/bin/sh
    
    ffmpeg -loop_input -f image2 -i black_video.png -r 1 -vcodec flv -i $1 -acodec copy -qscale 2 -g 5 -cmp 3 -subcmp 3 -mbd 2 $2 -shortest
    
    yamdi -i $2 -o $2-tmp
    
    rm $2mv $2-tmp $2
  3. Placer l’image black_video.png (en téléchargement ici) dans le même dossier que le script mp3toflv.sh.
  4. Donner les droits d’exécution au script:
    chmod 755 mp3toflv.sh

L’appel à ce script se fait de la manière suivante:

./mp3toflv.sh /path/to/source.mp3 /path/to/output.flv

Une fois le fichier flv obtenu par cette méthode, il suffit de le lire avec un lecteur de mp3 en flash.
Par exemple, le lecteur JW Player qui peut être utilisé pour ne reproduire que du son.

Il est nécessaire de préciser dans la playlist xspf pour JW Player le mode de streaming par le biais d’une balise meta:

...
<track>
… <location>http://www.host.com/directory/file.flv</location> <meta rel=”provider”>http</meta> …
</track> …

Cette méthode peut être testée par le biais de la radio SupaLame, qui utilise ce modèle pour offrir le streaming de sessions audios d’une durée supérieure à 4h stockées en un seul fichier.

  • Share/Save/Bookmark

Traduction des cantons suisses en français dans Magento

Par défaut, les cantons suisses sont présentés en allemand dans Magento, et ce même après l’installation des traductions FR. Il est nécessaire d’exécuter le code SQL suivant pour ajouter les traductions françaises:

INSERT INTO `directory_country_region_name` (`locale`, `region_id`, `name`) VALUES
('fr_FR', 104, 'Argovie'),
('fr_FR', 105, 'Appenzell Rhodes-Intérieures'),
('fr_FR', 106, 'Appenzell Rhodes-Extérieures'),
('fr_FR', 107, 'Berne'),
('fr_FR', 108, 'Bâle-Campagne'),
('fr_FR', 109, 'Bâle-Ville'),
('fr_FR', 110, 'Fribourg'),
('fr_FR', 111, 'Genève'),
('fr_FR', 112, 'Glaris'),
('fr_FR', 113, 'Grisons'),
('fr_FR', 114, 'Jura'),
('fr_FR', 115, 'Lucerne'),
('fr_FR', 116, 'Neuchâtel'),
('fr_FR', 117, 'Nidwald'),
('fr_FR', 118, 'Obwald'),
('fr_FR', 119, 'Saint-Gall'),
('fr_FR', 120, 'Schaffhouse'),
('fr_FR', 121, 'Soleure'),
('fr_FR', 122, 'Schwytz'),
('fr_FR', 123, 'Thurgovie'),
('fr_FR', 124, 'Tessin'),
('fr_FR', 125, 'Uri'),
('fr_FR', 126, 'Vaud'),
('fr_FR', 127, 'Valais'),
('fr_FR', 128, 'Zoug'),
('fr_FR', 129, 'Zurich');

Source: http://www.inthebox.ch/2009/06/25/494-gestion-des-cantons-dans-magento/ (offline) (cache)

  • Share/Save/Bookmark

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