PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Maximale Anzahl der Filehandler



Andy1988
08-12-2006, 22:45
Hallo,
Ich schreib mir grade ein Script, dass alle Mails in bestimmten Ordnern meiner Mailboxen in nen Temp-Ordner verschiebt und dann dem Spamassasin diese Mails als Spam beibringt.

Um jede Mailbox bei jeder Domain zu durchlaufen brauche ich 3 oder 4 Schleifen, bei denen halt die Ordner durchsucht werden.
Jetzt hab ich das Problem, dass PHP bei der letzten Schleife mit der Fehlermeldung "Warning: readdir(): 7 is not a valid Directory resource in /root/sa-learn.php on line 40" abbricht.

Ich schließe den Filehandler vorher auch nicht. Wenn ich ihn mit echo ausgeben lasse, erhalte ich "Resource id #7". Sollte stimmen.

Gibts da irgendwie ne Begrenzung wie viele Filehandler man öffnen kann in PHP? Aber wenn ja, dann liegt die doch nicht bei 3 oder 4 oder?
Und das System selber kann auch nicht so viele Handler offen haben.
In der Config hab ich nichts dazu gefunden.

Hier mein Script... Die Kommentare sind mal Englisch, mal Deutsch. Nicht gut, aber ich bin ja auch noch nicht fertig mit dem Script:

#!/usr/bin/php
<?php

###################### CONFIG ######################

$tmpdir = "/tmp/salearn"; #WITHOUT slash at the end
$maildir = "/home/vmail"; #WITHOUT slash at the end

###################### SCRIPT ######################
//Don't edit anything unless you know what you are doing!

echo "Starting sa-learn.php at " . date("j.n.y H:i:s") . "\n";

echo "Creating " . $tmpdir . " and subdirs\n";
mkdir($tmpdir);
mkdir($tmpdir . "/ham");
mkdir($tmpdir . "/spam");

echo "Moving all Messages into temporary Folders\n";
if($dir = opendir($maildir))
{
while(($domaindir = readdir($dir)) != false) //Alle Domains durchgehen
{
if($domaindir != "deleted-maildirs" && is_dir($maildir . "/" . $domaindir) && $domaindir != "." && $domaindir != "..") //Nur Ordner und nicht deleted-maildirs
{
echo $domaindir . "\n";
if($accounts = opendir($maildir . "/" .$domaindir))
{
while(($accountdir = readdir($accounts)) != false) //Alle Accounts durchgehen
{
if(is_dir($maildir . "/" . $domaindir . "/" . $accountdir) && $accountdir != "." && $accountdir != "..") //Nur Verzeichnisse
{
echo $accountdir . "\n";
if(file_exists($maildir . "/" . $domaindir . "/" . $accountdir . "/.Spam.Learn-Spam")) //Only go on if spam learning dir exists
{
if($mails = opendir($maildir . "/" . $domaindir . "/" . $accountdir . "/.Spam.Learn-Spam/cur")) //Open Spamdir for learning
{
echo $mails."\n";
echo $maildir . "/" . $domaindir . "/" . $accountdir . "/.Spam.Learn-Spam/cur";
while(($mail = readdir($mails)) != false)
{
if(!is_dir($maildir . "/" . $domaindir . "/" . $accountdir . "/.Spam.Learn-Spam/cur/" . $mail))
{
//copy($maildir . "/" . $domaindir . "/" . $accountdir . "/.Spam.Learn-Spam/cur/" . $mail, $tmpdir . "/spam");
}

closedir($mails);
}
}
else
echo "ERROR while opening Maildir " . $maildir . "/" .$domaindir . $accountdir . "/.Spam.Learn-Spam/cur";
}
else
echo "INFO: Spam learning dir doesn't exist in " . $maildir . "/" . $domaindir . "/" . $accountdir . "\n";
}
}
closedir($accounts);
echo "closed accounts\n";
}
else
echo "ERROR while opening Maildir " . $maildir . "/" .$domaindir;
}
}

closedir($dir);
echo "closed dir\n";
}
else
echo "ERROR while opening Maildir " . $maildir;


echo "Cleaning up...\n";
recursiveRemoveDirectory($tmpdir);



function recursiveRemoveDirectory($path)
{
$dir = new RecursiveDirectoryIterator($path);
foreach(new RecursiveIteratorIterator($dir) as $file)
{
unlink($file);
}

foreach($dir as $subdir)
{
if(!@rmdir($subdir))
{
recursiveRemoveDirectory($subdir);
}
}
rmdir($path);
}

?>

Romanday
09-12-2006, 09:39
Fehlermeldung "Warning: readdir(): 7 is not a valid Directory resource in /root/sa-learn.php on line 40" abbricht.

Ich schließe den Filehandler vorher auch nicht. Wenn ich ihn mit echo ausgeben lasse, erhalte ich "Resource id #7". Sollte stimmen.

Gibts da irgendwie ne Begrenzung wie viele Filehandler man öffnen kann in PHP? Aber wenn ja, dann liegt die doch nicht bei 3 oder 4 oder?
Und das System selber kann auch nicht so viele Handler offen haben.
In der Config hab ich nichts dazu gefunden.


Ne mit Filehandler hat das nix zu tun.
Schau dir mal die Dateifunktionen von PHP an.
Unter Linux gibt es nicht nur Dateien und Verzeichnisse. Es fehlen
einfach einige Prüfungen.



Hier mein Script... Die Kommentare sind mal Englisch, mal Deutsch. Nicht gut, aber ich bin ja auch noch nicht fertig mit dem Script:


Es das wirklich dein Script, oder Copy/Paste mit ein wenig Mauschel Mauschel oben drauf? :D

Wenn Du es richtig machen willst, schreib das Ding neu.
So schwer ist das nicht, und blickst du auch durch.
Tip: php -q + nimm ne Recursion für deine Verzeichnisse.
Das ist schneller.

Andy1988
09-12-2006, 16:16
Ja... Ist mein Script.

Das komische ist nur, dass das Verzeichnis, dass ich mit opendir() öffne auch wirklich ein Verzeichnis ist. Und keine Datei oder ein Link oder sonst was.

Romanday
09-12-2006, 18:19
Ja... Ist mein Script.

Das komische ist nur, dass das Verzeichnis, dass ich mit opendir() öffne auch wirklich ein Verzeichnis ist. Und keine Datei oder ein Link oder sonst was.

Mag sein, aber irgendwo hast 1 oder mehrere Prüfungen zu wenig.
Sonst würde keine Fehlermeldung kommen. opendir ist ja auch richtig,
bloß die Fehlermeldung bezieht sich auf readdir().

Mach mal ein Backup Verzeichnis mit wenig Files und Dir und laß dir
anzeigen was verschoben wurde. Dann kannst du doch viel schneller
herausfinden wo der Fehler ist.

Ich würde auch mal eine Fehlermeldung mit is_readable() einbauen.

michael.sprick
10-12-2006, 09:48
Hallo Andy1988,

Dieser codeteil ist verantwortlich für den Fehler:



while(($mail = readdir($mails)) != false)
{
if(!is_dir($maildir . "/" . $domaindir . "/" . $accountdir . "/.Spam.Learn-Spam/cur/" . $mail))
{
//copy($maildir . "/" . $domaindir . "/" . $accountdir . "/.Spam.Learn-Spam/cur/" . $mail, $tmpdir . "/spam");
}
closedir($mails);
}


Vermutlich siehst Du das Problem jetzt schon selber...
Beim ersten Durchlauf der while-Schleife schließt Du das Filehandle $mails wieder... damit schlägt der nächste Leseversuch von readddir natürlich fehl, weil das angegebene Filehandle ja garnicht mehr exisitert...

richtig wäre also:


while(($mail = readdir($mails)) != false)
{
if(!is_dir($maildir . "/" . $domaindir . "/" . $accountdir . "/.Spam.Learn-Spam/cur/" . $mail))
{
//copy($maildir . "/" . $domaindir . "/" . $accountdir . "/.Spam.Learn-Spam/cur/" . $mail, $tmpdir . "/spam");
}
}
closedir($mails);


hth, Michael

undefined
10-12-2006, 10:54
Also was du vorhast solltest du eher mit einem Shell Script und Cron machen.
Wenn du das Unbedingt mit PHP machen willst werfe die Schleifen weg und sehe dir die Imap Funktion in PHP an. Denn es ist Wichtig das die Nachrichten geflaggt werden. Sonst haben dein E-Mail Clienten massive Probleme


public function SetSpamMailByID( $id = 0 )
{
if ( (int)$id == 0 )
return false;

// DebugToLog( array( $Header, imap_last_error() ) );
$Header = imap_headerinfo( $this->IMAP, $id );
if ( is_object( $Header ) && (int)$Header->Msgno >= 1 )
{
imap_setflag_full( $this->IMAP, $Header->Msgno, '\\Seen \\Flagged' );
if ( array_key_exists( 'Spam', $this->MBOXES ) )
{
$b = imap_mail_move( $this->IMAP, $Header->Msgno, "INBOX.Spam" );
imap_expunge( $this->IMAP );
// DebugToLog( $b );
return $b;
} else
return false;
} else
return false;
}

Mit Cron - Das ist im Übrigen auch meine Variante - geht das schneller.
Denn es gibt nur einen Benutzer der lernen muss das ist entweder spamd oder der amavis Daemon.
Bei mir sieht jede Stunde cron.hourly in Jeden Benutzer Spam Postfach nach Mails.


#!/bin/bash
umask 022

PATH=/sbin:/bin:/usr/sbin:/usr/bin
export PATH

# get information from /etc/sysconfig
if [ -f /etc/sysconfig/cron ] ; then
. /etc/sysconfig/cron
fi

VIRTUAL=/var/spool/virtual_mailboxes

AMAVISD_DB=/var/spool/amavis/var
VIRTUAL_DB=/var/spool/virtual_mailboxes/my-domain.de

if [ -d $VIRTUAL ] ; then
echo "sa-learn [`date +"%T"`]" >> /var/log/spamassassin-sa-learn.log
for i in `find $VIRTUAL -mindepth 2 -maxdepth 3 -type d` ; do
if [ -d $i/.Spam ] ; then
for mfile in `find $i/.Spam -type f -exec grep -l '^X\-' {} \;` ; do
if [ ! -n "`grep 'application\/pgp' $mfile`" ] ; then
echo $mfile >> /var/log/spamassassin-sa-learn.log
/usr/bin/sa-learn --dbpath $AMAVISD_DB/.spamassassin --spam $mfile > /dev/null
/usr/bin/sa-learn --dbpath $VIRTUAL_DB/.spamassassin --spam $mfile > /dev/null
rm -f $mfile
fi
done
rm -f $i/.Spam/*/.avrc
fi
done
chown -R vscan.vscan $AMAVISD_DB
chown -R popuser.popuser $VIRTUAL_DB
fi
exit 0


Ich füttere in diesem Fall Zwei Benutzer einmal Amavis das von Postfix aufgerufen wird und einmal Virtual was ein ACL Postfach von Courier ist.

Andy1988
11-12-2006, 14:57
OK... Überzeugt!
Shellscript ist eindeutig besser ;)

Danke für deine Variante!

edit:
Eine Frage:
Was bewirkt das Löschen dieser Datei?

rm -f $i/.Spam/*/.avrc

undefined
12-12-2006, 10:44
Sie beinhaltet den MBOX Index.