Search code examples
phpcron

Saving an image from a URL in a PHP script not working through a cron job but script is working? Is it possible to save it?


I am trying to run a cron job on a shared host. The cron job is working and the script is running and entering data to a table but the problem is when it reaches the point where it must save an image, it is not doing it. I need please to know why?

To tell you what I found out: -I found out that for a script to run through a cron job, you must put the connection of the database in the same file and not include it

So here is my script with credentials being hidden:

$start_time = microtime(true); 

define("DB_HOST", "*******");
define("DB_USER", "*******");
define("DB_PASS", "*******");
define("DB_NAME", "*******");

$connection = mysqli_connect(DB_HOST, DB_USER, DB_PASS, DB_NAME);

//define('SITE_ROOT', $_SERVER['DOCUMENT_ROOT']);

//include "create_thumbnail.php";

// the news feeds table name is feeds_list

$query_count = "SELECT COUNT(*) FROM youtube_channels_feed_list WHERE active = 1";

$result_count = mysqli_query($connection, $query_count);

$count = mysqli_fetch_array($result_count);

$count_shift = array_shift($count);

if($count_shift > 0) {

    $query_fetch = "SELECT * FROM youtube_channels_feed_list WHERE active = 1";

    $result_fetch = mysqli_query($connection, $query_fetch);

    while($row = mysqli_fetch_assoc($result_fetch)) {

        $feed_id = $row["id"];
        $feed_name = strtolower($row["feed_name"]);
        $feed_url = $row["feed_url"];
        $feed_region = $row["feed_region"];
        $feed_length = $row["feed_length"];
        $subject_id = $row["subject_id"];
        $feed_source_url = $row["feed_source_url"];

        $url = $feed_url;
        $xml = simplexml_load_file($url);

        if($xml === false){
            //echo "Operation failed<br/><br/>";
        } else {

            $count = 0;
            
            for($i = 0; $i < $feed_length; $i++) {

                $count++;

                //echo "<br/><b><i>".$feed_name.": ------</i></b><br/><br/>";
                //echo "Feed Length is: ".$feed_length."<br/><br/>";

                // because item 0 is about the site and not news
                $title = $xml->entry[$i]->title;
                $title = str_replace("'", "&#39;", $title);
                $title = str_replace('"', "&#34;", $title);

                $link = $xml->entry[$i]->link->attributes()['href'];

                $pubDate = $xml->entry[$i]->published;
                $pubDate = strtotime($pubDate);

                $insert_date = time();

                $image_outer_link = $xml->entry[$i]->children( 'media', True )->group->children( 'media', True )->thumbnail->attributes()['url'];
                
                //echo $image_outer_link . "<br/>";
                    
                // for ignore to work we must make the title field in table UNIQUE
                $query1 = "INSERT IGNORE INTO youtube_videos_testing (title, link, pubDate, channel_feed_id, subject_id, insert_date) VALUES('$title', '$link', $pubDate, $feed_id, $subject_id, $insert_date)";

                if($result = mysqli_query($connection, $query1)){

                    $the_last_inserted_id = mysqli_insert_id($connection);
                    echo "last inserted id: " . $the_last_inserted_id . "<br>";

                    $new_image_link1 = "video-" . $the_last_inserted_id . ".jpg";

                    $new_image_link_thumb = "youtube-video-thumb-" . $the_last_inserted_id . ".jpg";

                    $query2 = "UPDATE youtube_videos_testing SET image = '$new_image_link_thumb' WHERE id = " . $the_last_inserted_id;
                    //echo $query2. "<br>";
                    $result2 = mysqli_query($connection, $query2);

                    $affected_rows = mysqli_affected_rows($connection);
                    //echo "affected_rows = " . $affected_rows;
                    if($affected_rows > 0) {

                        $query3 = "UPDATE youtube_videos_testing SET updated = 1 WHERE id = " . $the_last_inserted_id;
                        //echo $query2. "<br>";
                        $result3 = mysqli_query($connection, $query3);

                        // HERE IS WHERE THE PROBLEM IS HAPPENING
                        $target_path = $_SERVER['DOCUMENT_ROOT'] . "/admin/uploads/youtube_videos_testing/" . $new_image_link1;


                        echo $target_path . "<br>";
                        
                        // Open the file to get existing content
                        $data = file_get_contents($image_outer_link);

                        // Write the contents back to a new file
                        file_put_contents($target_path, $data);

                        

             
                    }
                }
                
                
            }

            //echo "Count: " . $count . "<br>";

        }

    }

} else {

    //echo "database is empty";

}






// These lines should be placed at the end of the script to get the script running time
// End clock time in seconds 
$end_time = microtime(true); 

// Calculate script execution time 
$execution_time = ($end_time - $start_time); 

echo " Execution time of script = ".$execution_time." sec"; 

Solution

  • Chances are that the cron job runs either as a different user or with a different home directory than what you're expecting.

    Another usual source of trouble is that with crontab scripts, the $_SERVER array is not populated because they're not being run by a web server at all. You don't have DOCUMENT_ROOT, and so on.

    Since you seem able to write to the database, try saving in a text field in a debug table the result from the get_current_user() and getcwd() commands.

    Alternatively, if the first command in your script is

    chdir(__DIR__);
    

    this will ensure that the script is running from the directory in which it originates.

    If your script resides in your DOCUMENT_ROOT, then you can use __DIR__ instead of $_SERVER['DOCUMENT_ROOT']. Or you can add at the top

    if (!isset($_SERVER)) {
        $_SERVER = array();
    }
    $_SERVER['DOCUMENT_ROOT'] = __DIR__;
    

    to quickly fix things.

    Another solution, when available, is to have cron call your script as a Web page using lynx or curl:

    curl -sk http://yourwebserver.com/path/to/script.php > /dev/null 2>&1
    

    It is usually better to save the output to a log file to investigate possible errors (so, ">> /path/to/var/www/html/logs/debug.log" instead of "> /dev/null" -- notice the two >'s to append to a log rather than rewriting it each time).