0

I've got a handful of sites I need to hit via Cron. I didn't want to create 20 cron jobs, so I created one that hits a single PHP script on my development server. It looks like this:

<?php //This script will send out directives to send [some] emails to [people]

//Start new init with $ch1, $ch2, $ch3 etc
$ch1 = curl_init();
$ch2 = curl_init();
$ch3 = curl_init();
$ch4 = curl_init();
$ch5 = curl_init();
$ch6 = curl_init();
$ch7 = curl_init();
$ch8 = curl_init();
$ch9 = curl_init();
$ch10 = curl_init();
$ch11 = curl_init();
$ch12 = curl_init();
$ch13 = curl_init();
$ch14 = curl_init();
$ch15 = curl_init();
$ch16 = curl_init();
$ch17 = curl_init();
$ch18 = curl_init();
$ch19 = curl_init();

//Set URL and options
curl_setopt($ch1, CURLOPT_URL, 'http://site1.com/?key=mykey');
curl_setopt($ch1, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch2, CURLOPT_URL, 'http://site2.com/?key=mykey');
curl_setopt($ch2, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch3, CURLOPT_URL, 'http://site3.com/?key=mykey');
curl_setopt($ch3, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch4, CURLOPT_URL, 'http://site4.com/?key=mykey');
curl_setopt($ch4, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch5, CURLOPT_URL, 'http://site5.com/?key=mykey');
curl_setopt($ch5, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch6, CURLOPT_URL, 'http://site6.com/?key=mykey');
curl_setopt($ch6, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch7, CURLOPT_URL, 'http://site7.com/?key=mykey');
curl_setopt($ch7, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch8, CURLOPT_URL, 'http://site8.com/?key=mykey');
curl_setopt($ch8, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch9, CURLOPT_URL, 'http://site9.com/?key=mykey');
curl_setopt($ch9, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch10, CURLOPT_URL, 'http://site10.com/?key=mykey');
curl_setopt($ch10, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch11, CURLOPT_URL, 'http://site11.com/?key=mykey');
curl_setopt($ch11, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch12, CURLOPT_URL, 'http://site12.com/?key=mykey');
curl_setopt($ch12, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch13, CURLOPT_URL, 'http://site13.com/?key=mykey');
curl_setopt($ch13, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch14, CURLOPT_URL, 'http://site14.com/?key=mykey');
curl_setopt($ch14, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch15, CURLOPT_URL, 'http://site15.com/?key=mykey');
curl_setopt($ch15, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch16, CURLOPT_URL, 'http://site16.com/?key=mykey');
curl_setopt($ch16, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch17, CURLOPT_URL, 'http://site17.com/?key=mykey');
curl_setopt($ch17, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch18, CURLOPT_URL, 'http://site18.com/?key=mykey');
curl_setopt($ch18, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch19, CURLOPT_URL, 'http://site19.com/?key=mykey');
curl_setopt($ch19, CURLOPT_RETURNTRANSFER, 1);

//Create multiple cURL handlers
$mh = curl_multi_init();

//Add the handles
curl_multi_add_handle($mh, $ch1);
curl_multi_add_handle($mh, $ch2);
curl_multi_add_handle($mh, $ch3);
curl_multi_add_handle($mh, $ch4);
curl_multi_add_handle($mh, $ch5);
curl_multi_add_handle($mh, $ch6);
curl_multi_add_handle($mh, $ch7);
curl_multi_add_handle($mh, $ch8);
curl_multi_add_handle($mh, $ch9);
curl_multi_add_handle($mh, $ch10);
curl_multi_add_handle($mh, $ch11);
curl_multi_add_handle($mh, $ch12);
curl_multi_add_handle($mh, $ch13);
curl_multi_add_handle($mh, $ch14);
curl_multi_add_handle($mh, $ch15);
curl_multi_add_handle($mh, $ch16);
curl_multi_add_handle($mh, $ch17);
curl_multi_add_handle($mh, $ch18);
curl_multi_add_handle($mh, $ch19);

$active = null;

//Execute handles
do {
    $mrc = curl_multi_exec($mh, $active);
} while ($mrc == CURLM_CALL_MULTI_PERFORM);

while ($active && $mrc == CURLM_OK) {
    if (curl_multi_select($mh) != -1) {
        do {
            $mrc = curl_multi_exec($mh, $active);
        } while ($mrc == CURLM_CALL_MULTI_PERFORM);
    }
}

//Error Report
echo 'Errors for <strong>site1.com</strong>: '.curl_error($ch1).'<br />';
echo 'Error Count for site1.com: <strong>'.curl_errno($ch1).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site2.com</strong>: '.curl_error($ch2).'<br />';
echo 'Error Count for site2.com: <strong>'.curl_errno($ch2).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site3.com</strong>: '.curl_error($ch3).'<br />';
echo 'Error Count for site3.com: <strong>'.curl_errno($ch3).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site4.com</strong>: '.curl_error($ch4).'<br />';
echo 'Error Count for site4.com: <strong>'.curl_errno($ch4).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site5.com</strong>: '.curl_error($ch5).'<br />';
echo 'Error Count for site5.com: <strong>'.curl_errno($ch5).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site6.com</strong>: '.curl_error($ch6).'<br />';
echo 'Error Count for site6.com: <strong>'.curl_errno($ch6).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site7.com</strong>: '.curl_error($ch7).'<br />';
echo 'Error Count for site7.com: <strong>'.curl_errno($ch7).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site8.com</strong>: '.curl_error($ch8).'<br />';
echo 'Error Count for site8.com: <strong>'.curl_errno($ch8).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site9.com</strong>: '.curl_error($ch9).'<br />';
echo 'Error Count for site9.com: <strong>'.curl_errno($ch9).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site10.com</strong>: '.curl_error($ch10).'<br />';
echo 'Error Count for site10.com: <strong>'.curl_errno($ch10).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site11.com</strong>: '.curl_error($ch11).'<br />';
echo 'Error Count for site11.com: <strong>'.curl_errno($ch11).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site12.com.au</strong>: '.curl_error($ch12).'<br />';
echo 'Error Count for site12.com.au: <strong>'.curl_errno($ch12).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site13.com</strong>: '.curl_error($ch13).'<br />';
echo 'Error Count for site13.com: <strong>'.curl_errno($ch13).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site14.com</strong>: '.curl_error($ch14).'<br />';
echo 'Error Count for site14.com: <strong>'.curl_errno($ch14).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site15.com</strong>: '.curl_error($ch15).'<br />';
echo 'Error Count for site15.com: <strong>'.curl_errno($ch15).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site16.com</strong>: '.curl_error($ch16).'<br />';
echo 'Error Count for site16.com: <strong>'.curl_errno($ch16).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site17.com</strong>: '.curl_error($ch17).'<br />';
echo 'Error Count for site17.com: <strong>'.curl_errno($ch17).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site18.com</strong>: '.curl_error($ch18).'<br />';
echo 'Error Count for site18.com: <strong>'.curl_errno($ch18).'</strong><br /><br />';
echo '<hr />';
echo 'Errors for <strong>site19.com</strong>: '.curl_error($ch19).'<br />';
echo 'Error Count for site19.com: <strong>'.curl_errno($ch19).'</strong><br /><br />';


//Close handles
curl_multi_remove_handle($mh, $ch1);
curl_multi_remove_handle($mh, $ch2);
curl_multi_remove_handle($mh, $ch3);
curl_multi_remove_handle($mh, $ch4);
curl_multi_remove_handle($mh, $ch5);
curl_multi_remove_handle($mh, $ch6);
curl_multi_remove_handle($mh, $ch7);
curl_multi_remove_handle($mh, $ch8);
curl_multi_remove_handle($mh, $ch9);
curl_multi_remove_handle($mh, $ch10);
curl_multi_remove_handle($mh, $ch11);
curl_multi_remove_handle($mh, $ch12);
curl_multi_remove_handle($mh, $ch13);
curl_multi_remove_handle($mh, $ch14);
curl_multi_remove_handle($mh, $ch15);
curl_multi_remove_handle($mh, $ch16);
curl_multi_remove_handle($mh, $ch17);
curl_multi_remove_handle($mh, $ch18);
curl_multi_remove_handle($mh, $ch19);

curl_multi_close($mh);

echo 'Script Executed Successfully!'; // Just shows me the file is actually loading to completion
?>

Each of these sites is WordPress that's built to handle the query string.

<?php
    if( $_GET['key'] == 'mykey'){
        $network_array = wp_get_sites();

        foreach( $network_array as $site ){
            $temp = file_get_contents('http://'.$site['domain'].'/page-with-mail-script/?runkey=AnotherKey');
            $temp = '';
        }
    }
?>

At this point, the idea is to use the wp_get_sites() function to get an array of all of the sites on that particular network (these are all wordpress multisite). I use file_get_contents() to visit the site with a query string to run the script on that page.

That page template runs a wp_query for a list of emails to send, and one for a list of "contacts" to send them to, using Mandrill by MailChimp. This is that file:

get_header();

    do_action( 'genesis_before_content_sidebar_wrap' );
    ?>
    <div id="content-sidebar-wrap">
        <?php do_action( 'genesis_before_content' ); ?>
        <div id="content" class="hfeed">
            <?php
            if($_GET['key'] == 'AnotherKey'){
                #Start up contact query
                $contact_query = new WP_Query(array('post_type' => 'contacts', 'posts_per_page' => '-1'));
                $invite_query = new WP_Query(array('post_type' => 'invites', 'posts_per_page' => '-1'));

                #Let's use the get_posts method for a foreach loop option
                $contacts = $contact_query->get_posts();
                $invites = $invite_query->get_posts();

                #Loop through the contacts
                foreach( $contacts as $contact ){
                    $email_status = 'skipped.';
                    #Initiate the custom fields
                    $contact_custom = get_post_custom($contact->ID);

                    #Return custom fields as variables
                    $email_address = $contact_custom['email_address'][0]; //Where do we reach them?
                    $email_number = $contact_custom['email_number'][0]; //Which email do they need?
                    $last_email_date = $contact_custom['last_email_date'][0]; //When did they last get one?
                    //$phone_number = $contact_custom['phone_number']; // Phone Number (NOT USED 9-23-14)

                    #Let's get some other variables we need
                    $today = time();
                    $remove_me_link = '<a href="'.site_url().'/remove-me?email='.urlencode($email_address).'" target="_blank">Get Removed From This List</a>';

                    #If EMAIL_NUMBER is GREATER than zero, continue, otherwise skip (this is set to a negative value to remove them from the list)
                    if( $email_number > 0 ){
                        #We need to find the email to send them.
                        foreach( $invites as $invite ){
                            #Initiate the custom fields
                            $invite_custom = get_post_custom($invite->ID);

                            #Return custom fields as variables
                            $invite_number = $invite_custom['invite_number'][0]; //Which email is this?
                            $invite_delay = $invite_custom['invite_delay'][0]; //How long should we wait to send this one?
                            $forgiving_delay = $invite_delay * 86400; //Ex. 1, or 7 times a unix day
                            $forgiving_delay = $forgiving_delay - 28800; // Remove 8 hours from the timeframe, this allows some leway in server time discrepancies
                            $publish_date = get_the_time('U', $contact->ID); //Convert publish date to unix

                            #See if the invite number matches their required email number
                            if( $invite_number == $email_number ){
                                #It does! Now see if the proper delay has been met
                                if( empty($last_email_date) || $last_email_date == '' || $last_email_date < 9999 ){ //This means they're new. We need to wait until the delay after the PUBLISH date for this.
                                    if($today - $publish_date > $forgiving_delay){
                                        $to = $email_address;
                                        $subject = $invite->post_title;
                                        $message = '
                                        <html>
                                            <head>
                                                <title>'.$invite->post_title.'</title>
                                            </head>
                                            <body>
                                                <p>'.$invite->post_content.'</p>
                                                <br />
                                                <br />
                                                <p style="font-size: 10px;">This email was sent to you on behalf of <strong>'.$gv->organization.'</strong>, <strong>'.$gv->address.', '.$gv->city.' '.$gv->state.' '.$gv->zip_code.'</strong><br />If you have any questions, please send an email to <strong>'.$gv->author_email.'</strong> or call <strong>'.$gv->phone.'</strong>.</p>
                                                <p style="font-size: 10px;">Don\'t want to see this? '.$remove_me_link.'</p>
                                            </body>
                                        </html>';
                                        $message = str_replace('{contact_name}', $contact->post_title, $message);
                                        $message = str_replace('{contact_email}', $email_address, $message);
                                        $message = str_replace('{review_engine_url}', str_replace(array('http://', 'https://'), '', site_url()), $message);
                                        $message = str_replace('{google_url}', $gv->google_plus, $message);
                                        $message = str_replace('{yelp_url}', $gv->yelp, $message);
                                        $message = str_replace('{facebook_url}', $gv->like_box, $message);
                                        $message = str_replace('{review_site_one_url}', $gv->review_site_one_url, $message);
                                        $message = str_replace('{review_site_two_url}', $gv->review_site_two_url, $message);
                                        $message = str_replace('{review_site_three_url}', $gv->review_site_three_url, $message);
                                        $message = str_replace('{review_site_four_url}', $gv->review_site_four_url, $message);
                                        $message = str_replace('{superpages_url}', $gv->super_pages, $message);
                                        $message = nl2br($message);
                                        //$from = 'mailer@'.str_replace(array('http://', 'https://'), '', site_url());
                                        $headers  = 'MIME-Version: 1.0' . "\r\n";
                                        $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
                                        //$headers .= 'From: '.$from;
                                        $mail = wpMandrill::mail($to, $subject, $message, $headers);

                                        #If it succeeded, let's update post data in the contact
                                        if( $mail ){
                                            update_post_meta($contact->ID, 'email_number', $email_number + 1);
                                            update_post_meta($contact->ID, 'last_email_date', $today);
                                            $email_status = 'Good!';
                                        } else {
                                            $email_status = 'Bad.';
                                        }
                                    echo $contact->post_title.': <strong>'.$email_status.'</strong><br />';
                                    }
                                } else {
                                    if($today - $last_email_date > $forgiving_delay){ // This means they've gotten emails before, proceed as normal
                                        //trm_send_invite_email(); //WHAT DID THIS DO?
                                        $to = $email_address;
                                        $subject = $invite->post_title;
                                        $message = '
                                        <html>
                                            <head>
                                                <title>'.$invite->post_title.'</title>
                                            </head>
                                            <body>
                                                <p>'.$invite->post_content.'</p>
                                                <br />
                                                <br />
                                                <p style="font-size: 10px;">This email was sent to you on behalf of <strong>'.$gv->organization.'</strong>: <strong>'.$gv->address.', '.$gv->city.' '.$gv->state.' '.$gv->zip_code.'</strong><br />If you have any questions, please send an email to <strong>'.$gv->author_email.'</strong> or call <strong>'.$gv->phone.'</strong>.</p>
                                                <p style="font-size: 10px;">Don\'t want to see this? '.$remove_me_link.'</p>
                                            </body>
                                        </html>';
                                        $message = str_replace('{contact_name}', $contact->post_title, $message);
                                        $message = str_replace('{contact_email}', $email_address, $message);
                                        $message = str_replace('{review_engine_url}', str_replace(array('http://', 'https://'), '', site_url()), $message);
                                        $message = str_replace('{google_url}', $gv->google_plus, $message);
                                        $message = str_replace('{yelp_url}', $gv->yelp, $message);
                                        $message = str_replace('{facebook_url}', $gv->like_box, $message);
                                        $message = str_replace('{review_site_one_url}', $gv->review_site_one_url, $message);
                                        $message = str_replace('{review_site_two_url}', $gv->review_site_two_url, $message);
                                        $message = str_replace('{review_site_three_url}', $gv->review_site_three_url, $message);
                                        $message = str_replace('{review_site_four_url}', $gv->review_site_four_url, $message);
                                        $message = str_replace('{superpages_url}', $gv->super_pages, $message);
                                        $message = nl2br($message);
                                        //$from = $gv->organization.'@'.str_replace(array('http://', 'http:s//'), '', site_url());
                                        $headers  = 'MIME-Version: 1.0' . "\r\n";
                                        $headers .= 'Content-type: text/html; charset=iso-8859-1' . "\r\n";
                                        //$headers .= 'From: '.$from;
                                        $mail = wpMandrill::mail($to, $subject, $message, $headers);

                                        #If it succeeded, let's update post data in the contact
                                        if( $mail ){
                                            update_post_meta($contact->ID, 'email_number', $email_number + 1);
                                            update_post_meta($contact->ID, 'last_email_date', $today);
                                        } else {
                                            $email_status = 'Bad.';
                                        }
                                    }
                                    echo $contact->post_title.': <strong>'.$email_status.'</strong><br />';
                                }

                            }
                        } //End Invite Loop
                    } 
                } //End Contact loop
            } else {
                echo '<h1 class="entry-title">Hold on, partner!</h1>';
                echo '<p>You\'re not supposed to be here!</p>';
            } ?>
        </div><!-- end #content -->
        <?php do_action( 'genesis_after_content' ); ?>
        <div style="clear:both;"></div>
    </div><!-- end #content-sidebar-wrap -->
    <?php
    do_action( 'genesis_after_content_sidebar_wrap' );

get_footer();

I get a notification from the Cron Daemon saying that the script executed, by showing the "Script Executed Succesfully" echo in the first file that gets hit by the cron.

The problem is, the emails seem to get sent on the first couple sites, but then the rest remain untouched, as shown by a custom field in the "contact" post type.

Is the script timing out? Getting killed? Should I instead of going to each site in one file, go to each separately? Or should I used curl_init(), curl_setopt, and then remove the cURL before going to the next one?

Xhynk
  • 13,513
  • 8
  • 32
  • 69
  • What about checking your mail server logs? – divaka Apr 03 '15 at 22:47
  • We use Mandrill - does that still show up in there? – Xhynk Apr 03 '15 at 22:54
  • Not familiar with Mandril, unfortunately. Look for some error logs or something? You could take a look at this: http://stackoverflow.com/questions/21456680/why-is-my-mails-staying-in-backlog-of-mandrill and search where your backlog is :) – divaka Apr 03 '15 at 23:00
  • Instead of `array('http://', 'http:s//')`, you may want `array('http://', 'https://')`. – Cœur Oct 20 '19 at 10:47

2 Answers2

1

We were trying to do nearly the exact same thing, (Wordpress Multisite emails) and ran into a timeout problem with the built-in PHPMailer class (the wp_mail() function being a wrapper for it). My CRON script would always get to 100 emails, and then die. The script would echo that it finished sending, but I would only receive the first 100. Interestingly enough, when I split it between two Wordpress sites on the same server, I would get 50 emails sent on each site. I'm not familiar with Mandrill, but I wonder if you're running into a rate limit, initiating too many email sends in too short of a time period.

Is this executing the mail() function twice?

Perhaps change this:

$mail = wpMandrill::mail($to, $subject, $message, $headers);
#If it succeeded, let's update post data in the contact
if( $mail ){
update_post_meta($contact->ID, 'email_number', $email_number + 1);

To this:

if( $mail = wpMandrill::mail($to, $subject, $message, $headers) ) {
update_post_meta($contact->ID, 'email_number', $email_number + 1);
  • Oh you're right! I've swapped that code. As for the rate limit, that's not the case (it may be one, but it's not in this case). I know that because if it shuts down after 100, if I ran it again, it would do the next hundred, since it's designed to skip if it's not scheduled to send an email. I've ran one on a larger site sooo many times (with a lot of sites not using trhe feature at all, and most with 5-12 emails so far) :/ – Xhynk Apr 03 '15 at 23:27
0

Why are you opening 19 separate connect handlers for this? I don't know if this is causing the problems you're describing but it certainly wouldn't be helping.

Benco
  • 130
  • 9