Mailversand per Cron automatisieren

Divo1984

Erfahrenes Mitglied
Guten Abend,

ich habe folgende Klasse:

PHP:
<?php
require_once '../class/sub_classes/class_DB.php';
require_once '../class/phpmailer/class.phpmailer.php';

class cronMail{
	
	/**
	 * Die Betreffe 
	 * 
	 * @var string
	 */
	public $betreff1;	
	public $betreff2;
	public $betreff3;
	
	/**
	 * Die Texte
	 * 
	 * @var string
	 */
	public $text1;
	public $text2;	
	public $text3;	
	
	/**
	 * Die Userids für das Updaten nach erhalt der Cronmail
	 * 
	 * @var array
	 */
	public $update_1=array();	
	public $update2=array();	
	public $update3=array();
	
	/**
	 * Construct
	 */
	public function __construct(){
		$this->dbh=new DB();
		$this->mail=new PHPMailer();
	}
	
	/**
	 * Hole die Mailinfos anhand der ID
	 * 
	 * @param integer $id
	 */
	public function getMail($id){
		
		/**
		 * Konnekt zur Datenbank
		 * 
		 */
		$a=$this->dbh->conn();
		$erg=$a->query("SELECT * FROM c_mails WHERE id='$id'");
		
		/**
		 * Cronmail mit ID 1
		 */
		if($id=="1"){
			while($mail1=$erg->fetch_array()){
				//setze Betreff und Text
				$this->betreff1=$mail1['betreff'];
				$this->text1=$mail1['text'];
			}
		}
		
		/**
		 * Cronmail mit ID 2
		 */
		elseif($id=="2"){
			while($mail2=$erg->fetch_array()){
				//setze Betreff und Text
				$this->betreff2=$mail2['betreff'];
				$this->text2=$mail2['text'];
			}			
		}
		
		/**
		 * Cronmail mit ID 3
		 */
		elseif($id=="3"){
			while($mail3=$erg->fetch_array()){
				//setze Betreff und Text
				$this->betreff3=$mail3['betreff'];
				$this->text3=$mail3['text'];
			}
		}
	}
	
	/**
	 * Sende die Mail mit ID
	 * 
	 * @param integer $id
	 */	
	public function sendMail($id){
		
		/**
		 * Hole die Daten der Mail anhand der ID
		 * 
		 * @var integer
		 */
		$this->getMail($id);
		
		//PHPMailer Infos für den Versand
		$this->mail->SetFrom("kontakt@xxx.de", "xxx.de");
		
		/**
		 * Mail mit der ID 1 vorbereiten
		 */
		if($id=="1"){
			//Query für die Userabfrage 
			$query="";
			//PHPMailer Betreff und body definieren
			$this->mail->Subject=$this->betreff1;
			$this->mail->body=$this->text1;
		}
		
		/**
		 * Mail mit der ID 2 vorbereiten
		 */
		elseif($id=="2"){
			//Query für die Userabfrage
			$query="c_mail_1='1' AND";
			//PHPMailer Betreff und body definieren
			$this->mail->Subject=$this->betreff2;
			$this->mail->body=$this->text2;
		}
		
		/**
		 * Mail mit der ID 3 vorbereiten
		 */
		elseif($id=="3"){
			//Query für die Userabfrage
			$query="c_mail_2='1! AND";
			//PHPMailer Betreff und body definieren
			$this->mail->Subject=$this->betreff3;
			$this->mail->body=$this->text3;
		}

		//Konnekt zur DB um die Userdaten zu holen
		$a=$this->dbh->conn();
		//Abfrage mit vorbereitetem Query
		$erg=$a->query("SELECT * FROM b_receiver WHERE $query c_mail_$id='0'");
		
		/**
		 * Sende Mail 1
		 */
		if($id=="1"){
			while($empf1=$erg->fetch_array()){
				echo $empf1['u_email']."<br>";
				$this->update_1[]=$empf1['u_id'];
			}
		}
		
		/**
		 * Sende Mail 2
		 */
		elseif($id=="2"){
			while($empf2=$erg->fetch_array()){
				echo $empf2['u_email']."<br>";
				$this->update_2[]=$empf2['u_id'];
			}			
		}
		
		/**
		 * Sende Mail 3
		 */
		elseif($id=="3"){
			while($empf3=$erg->fetch_array()){
				echo $empf3['u_email']."<br>";
				$this->update_3[]=$empf3['u_id'];
			}			
		}
	}
	
	/**
	 * Update User nach Erhalt der Mail
	 * 
	 * @param integer $id (Mail ID)
	 * @param integer $user (UserID)
	 */
	public function update($id, $user){
		//Konnect zur Datenbank
		$a=$this->dbh->conn();
		
		/**
		 * User hat Mail 1 erhalten
		 */
		if($id=="1"){
			$a->query("UPDATE b_receiver SET c_mail_1='1' WHERE u_id={$user}");
		}
		
		/**
		 * User hat Mail 2 erhalten
		 */
		elseif($id=="2"){
			$a->query("UPDATE b_receiver SET c_mail_2='1' WHERE u_id={$user}");
		}
		
		/**
		 * User hat Mail 3 erhalten
		 */
		elseif($id=="3"){
			$a->query("UPDATE b_receiver SET c_mail_3='1' WHERE u_id={$user}");
		}
	}
}

?>

Wie zu sehen ist, habe ich die Klasse so erstellt, das ein Versand per Cron von 3 Mails machbar wäre...

Ich habe mir nun aber gedacht, dass ich evtl. noch ne weitere Mailvorlage zum Versand bereitstellen mag und nicht unbedingt wieder an die Datei möchte. Habt ihr vllt. nen Lösungsansatz um das ganze zu automatisieren?

Meine Idee wäre halt zu zählen, wie viele Vorlagen sind vorhanden in der DB - aber wie passe ich meine Klasse dementsprechend an? Ich muss ja meine Variablen vorbereiten sowie deklarieren, da stehe ich grad vor einem großen ?

Ich hoffe, ihr könnt mir hier weiterhelfen!

P.S. Ja ich weiß, dass ich statt nen Versand hier nen echo Befehl drin habe, das ist zu Testzwecken so gemacht;)
 
Annahme:
Du rufst jede der Methoden, oder zumindest eine, mit ner jeweiligen ID auf, was wohl die Vorlage meint.
Aufruf quasi, nachdem ich versucht hab den Code zu interpretieren:
PHP:
$cronMail->sendMail(1);
$cronMail->update(1, 1); //wo auch immer der User herkommt

?
Wenn das so grob hinhaut kannst du dir die Abfragen innerhalb der Klassen so ziemlich komplett sparen (wenn nicht dann schreib bitte noch ne kleine Erklärung dazu und ignoriere das Folgende; ich hatte grad einfach Lust in deiner Klasse rumzurühren).

PHP:
<?php
require_once '../class/sub_classes/class_DB.php';
require_once '../class/phpmailer/class.phpmailer.php';

class cronMail{

    /**
     * Die ID der Vorlage 
     * 
     * @var int
     */

    private $id;
    
    /**
     * Der Betreff 
     * 
     * @var string
     */
    private $betreff;
    
    /**
     * Der Text
     * 
     * @var string
     */
    private $text;
    
    /**
     * Die Userids für das Updaten nach erhalt der Cronmail
     * 
     * @var array
     */
    private $update=array();

    /**
     * Die Verbindungsressource der Datenbank
     * 
     * @var ressource
     */
    private $connection;
    
    /**
     * Construct
     */
    public function __construct(){
        $this->dbh=new DB(); /* hier scheint was zu fehlen? 
        Die Eigenschaft dbh ist nirgendwo definiert */
        $this->mail=new PHPMailer(); //hier och
		//damit wir nicht mehrfach connecten müssen schreiben wir's in ne Eigenschaft
		$this->connection=$this->dbh->conn();
    }

    /**
     * Setze VorlagenID
     * 
     * @param integer $id
     */
    public function setID($id){
	    /* setze die Eigenschaft auf Parameter $id, 
            damit $id nicht an jede Methode übergeben werden muss */
	    $this->id = $id;
    }
    
    /**
     * Hole die Mailinfos anhand der ID
     */
    private function getMail(){ /* da getMail von sendMail aufgerufen wird 
    kann die ruhig private sein */
     
        $erg=$this->connection->query("SELECT * FROM c_mails WHERE id='".$this->id."'");

	    while($mail=$erg->fetch_array()){
            //setze Betreff und Text
            $this->betreff=$mail['betreff'];
            $this->text=$mail['text'];
        }
    }
    
    /**
     * Sende die Mail mit ID
     */    
    public function sendMail(){
     
        $this->getMail(); 
        /* würde hier grundsätzlich eine Art if(methode) setzen und in getMail() nur true zurückgeben, 
        wenn das Query usw. geklappt hat*/
        
        //PHPMailer Infos für den Versand
        $this->mail->SetFrom("kontakt@xxx.de", "xxx.de");
        
	    /* Ausgehend von der Logik: wenn $id > 1, 
            dann rufe das Query mit c_mail($id-1) auf */
	    if($this->id > 1) $where = "c_mail_".($this->id-1)." = 1 AND";
	    else $where = ""; 
            //ich nehm hier $where als Variable weil $query einfach falsche Assoziationen weckt (zumindest bei mir)

	    $this->mail->Subject=$this->betreff;
        $this->mail->body=$this->text;
        

        //Abfrage mit vorbereitetem Query
        $erg=$this->connection->query("SELECT * FROM b_receiver WHERE ".$where." c_mail_".$this->id." = 0");
        
        /**
         * Sende Mail oder tu einfach so
         */
	    while($empf=$erg->fetch_array()){
            echo $empf['u_email']."<br>";
            $this->update[]=$empf['u_id'];
        }
      
    }
    
    /**
     * Update User nach Erhalt der Mail
     */
    public function update(){
	    /* keine Ahnung wo die aufgerufen wird, könnte am Ende von sendMail geschehen, dann kannst du die auch privatisieren */
	    /* scheinbar hast du an anderer Stelle das user-Array durchgerödelt, ich bin mal so dreist und verleg das hierhin */
			
	    while(list($key, $userid) = each($this->update)){
		    /* hier hast du plötzlich ne andere Logik drin. jetzt entspricht die Zahl bei c_mail_ wieder der id. */
            /* Ich bin geringfügig verwirrt und übernehm das einfach mal */
		    $a->query("UPDATE b_receiver SET c_mail_".$this->id." ='1' WHERE u_id=".$userid);
	     }
    }
}

?>

Aufruf wäre dann theoretisch so:

PHP:
$cronMail = new cronMail();
$cronMail->setID(1);
$cronMail->sendMail();

So. Damit das Ganze auch wirklich dynamisch wird, feuerst du vor dem Aufruf ein Query ab á "Hol mir alle VorlagenIDs die es gibt". Die IDs wirfst du in ein Array und gehst dann beim Aufruf dieses Array durch, ungefähr so:

PHP:
$cronMail = new cronMail();
/* Query & Arrayfüllung */
while(list($key, $vorlage) = each($filledArray)){
    $cronMail->setID($vorlage);
    $cronMail->sendMail();
}

Natürlich alles absolut ungetestet.


Schalom.
 
Zuletzt bearbeitet:
Arrays wären dafür ganz nützlich.
Leg' im aufgerufenen Script ein Array an, dass Instanzen deiner cronMail-Klasse aufnimmt.
Also:
PHP:
<?php

class cronMail  {
...
}

$mails = array();

foreach($_REQUEST['id'] as $mail_id)  {
    $mails[] = new cronMail($mail_id);
    // Attribute zuweisen (und Mail versenden?)
    ...
}

// eventuell eine extra Schleife, um die Mails zu versenden
foreach($mails as $mail)   {
    ...
}

?>

Dann kannst du das Script so aufrufen:
Code:
cronmail.php?id[]=13&id[]=231&id[]=721&...
 
Naja, für 3 nicht... habe hier nicht alles durchgelesen, nur sowas wie sendmail() in ner while-Schleife lässt mich immer stutzen.... Man sieht ja immer die tollsten Sachen .
 
Ja bei 100 Mails würde ich auch stutzig werden, aber da wird sich der TO hoffentlich schon selber Gedanken gemacht haben.

Nur mal interessehalber: Wie versendest du 100 Mails? Ich bin selber noch nicht in den Genuss gekommen, das machen zu müssen, aber man weiß ja nie ... :)
 
Keine Ahnung, ich kam auch noch nie in den genuss :P

Wahrscheinlich würde ich mir mal die Mailer-Klasse des von mir genutzten Frameworks mal genauer ansehen, wie das dort gehandhabt wird und ob ich die nicht verwenden kann. Ansonsten würde ich das PEAR-Package verwenden ;)
 
Moin,

so das Problem habe ich nun folgendermaßer gelöst:

PHP:
<?php
require_once '../class/sub_classes/class_DB.php';
require_once '../class/phpmailer/class.phpmailer.php';

class cronMail{
	
	/**
	 * Die Betreffe 
	 * 
	 * @var string
	 */
	private $betreff;	
	
	/**
	 * Die Texte
	 * 
	 * @var string
	 */
	private $text;	

	/**
	 * Datenbankverbindung
	 * 
	 * @var NULL
	 */
	private $dbh=NULL;

	private $connect;

	
	public $anz=0;

	/**
	 * Construct
	 */	
	public function __construct(){
		$this->dbh=new DB();
		$this->mail=new PHPMailer();
		
		$this->connect=$this->dbh->conn();
	}
	
	/**
	 * Hole die Mailinfos anhand der ID
	 * 
	 * @param integer $id
	 */
	public function getMail($id){

		$erg=$this->connect->query("SELECT * FROM c_mails WHERE id='$id'");
		
		/**
		 * Cronmail einlesen
		 */		
		while($mail=$erg->fetch_array()){
			//setze Betreff und Text
			$this->betreff=$mail['betreff'];
			$alink="<a href=\"{$mail['link']}\">";
			$linkend="</a>";
			//Link einfügen
			$search=array("{link}", "{link_end}");
			$replace=array($alink, $linkend);			
			$this->text=$mail['text'];	
			$this->text=str_replace($search, $replace, $this->text);		
		}	
	}
	
	/**
	 * Sende die Mail mit ID
	 * 
	 * @param integer $id
	 */	
	public function sendMail($id){
		
		/**
		 * Hole die Daten der Mail anhand der ID
		 * 
		 * @var integer
		 */
		$this->getMail($id);
		
		//PHPMailer Infos für den Versand
		$this->mail->SetFrom("kontakt@xxx.de", "xxx.de");

		//PHPMailer Betreff definieren
		$this->mail->Subject=$this->betreff;
		
		
		//Wenn ID >1 dann bereite AND vor
		if($id!="1"){
			$mail_id=$id-1;
			$time=(time()-80000);
			$and="AND c_mail_{$mail_id}='1' AND last_c_mail<'{$time}'";
		}
		
		//Abfrage mit vorbereitetem AND 
		#echo"SELECT * FROM b_receiver WHERE c_mail_{$id}='0' {$and}".time();;
		$erg=$this->connect->query("SELECT * FROM b_receiver WHERE c_mail_{$id}='0' {$and}");
		
		
		//Wenn min 1 Empfänger dann Durchlaufe den Versand und update
		if($erg->num_rows!=0){
			while($empf=$erg->fetch_assoc()){
				$this->mail->AddAddress($empf['u_email']);
				
				$this->text=str_replace("{vname}", $empf['u_vname'], $this->text);
				$this->mail->body=$this->text;
				$this->mail->Send();
				$this->update($id, $empf['u_id']);
			}		
		}else{
			echo"Keine Empfänger für Nl ID {$id}<br>";
		}		
	}
	
	/**
	 * Update User nach Erhalt der Mail
	 * 
	 * @param integer $id (Mail ID)
	 * @param integer $user (UserID)
	 */
	public function update($id, $user){

		if($id!="1"){
			$mail_id=$id-1;
			$time=time()-80000;
			$and="AND c_mail_{$mail_id}='1' AND last_c_mail<'{$time}'";
		}
		$time2=time();
		#echo"UPDATE b_receiver SET c_mail_{$id}='1', last_c_mail='{$time2}' WHERE u_id='{$user}' {$and}";
		$this->connect->query("UPDATE b_receiver SET c_mail_{$id}='1', last_c_mail='{$time2}' WHERE u_id='{$user}' {$and}");
	}
	
	public function getAnz(){
		$erg=$this->connect->query("SELECT * FROM c_mails");
		$this->anz=$erg->num_rows;
	}
}

//Ab hier wird ausgeführt!
$cronmail=new cronMail();

$cronmail->getAnz();

for($i=1; $i<=$cronmail->anz; $i++){
	$cronmail->sendMail($i);
}

?>

Warum nutze ich send? Weil mir der PHPMailer alles bietet was ich haben will... Ins PEAR hab ich mich noch nicht eingelesen, würde da wohl eher Zend vorziehen...

Zur Erklärung bei der Klasse- ich habe dort den Updatebefehl mit drin. Dieser setzt nen Timestamp+80000 in die DB, damit nicht jeder User beim ersten Versand alle Mails erhält - so ist gesichert, dass immer nur eine Mail an jeden versendet wird:)
 
Zurück