Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run a cron job on a CodeIgniter controller that all the URL does is run a query from an API, update the DB & send emails (from within CI)?

I have a web application that runs a query on an api, gets new information, changes the variables in the database and sends emails if needed (compares old and new variables).

I work with Ubuntu Server, and I tried several variations to run this.

my controller looks like this:

class Cli_only extends CI_Controller {

    public function __construct() {

       parent::__construct();
        is_cli() OR show_404(); // If cronjob ! 

       $this->load->model('kas_model');

        // Sets the server not to have a time out. 
        ini_set('max_execution_time', 0); 
        ini_set('memory_limit', '-1');      
        // Expand the array displays
        ini_set('xdebug.var_display_max_depth', 5);
        ini_set('xdebug.var_display_max_children', 256);
        ini_set('xdebug.var_display_max_data', 1024);
    }



    // This function has to run every day using a corn job. 
    public function cron_job(){
        // does stuff...
    }

So at first I tried using the regular 'curl' command on my cronjob:

15 15 * * * http://10.0.1.666/tools/Cli_only/cron_job

and I got this error in the log file:

Dec 6 15:30:01 MYserver CRON[1134]: (root) CMD (curl http://10.0.1.66/tools/Cli_only/cron_job) 
Dec 6 15:30:02 MYserver CRON[1133]: (CRON) info (No MTA installed, discarding output)

running a quick google on this and I noticed that I have to install "postfix" on my server, and I did. I restarted cron and get:

Dec  6 16:26:01 MYserver cron[2663]: (root) RELOAD (crontabs/root)
Dec  6 16:26:01 MYserver CRON[2703]: (root) CMD (curl http://10.0.1.666/tools/Cli_only/cron_job)
Dec  6 16:26:01 MYserver postfix/pickup[2479]: 23430102E11: uid=0 from=<root>
Dec  6 16:26:01 MYserver postfix/cleanup[2707]: 23430102E11: message-id=<20151206142601.23430102E11@MYserver>
Dec  6 16:26:01 MYserver postfix/qmgr[2480]: 23430102E11: from=<root@MYserver>, size=2058, nrcpt=1 (queue active)
Dec  6 16:26:01 MYserver postfix/local[2709]: 23430102E11: to=<root@MYserver>, orig_to=<root>, relay=local, delay=0.02, delays=0.01/0/0/0, dsn=2.0.0, status=sent (delivered to mailbox)
Dec  6 16:26:01 MYserver postfix/qmgr[2480]: 23430102E11: removed

Still, no changes on the DB - and if there were - CodeIgniter has a working mailing configurations that should work from just running the URL.

I tried running things like this:

14 16 * * * wget -O - http://10.0.1.666/tools/Cli_only/cron_job >/dev/null 2>&1

14 16 * * * curl -O - http://10.0.1.666/tools/Cli_only/cron_job >/dev/null 2>&1

14 16 * * * GET -O - http://10.0.1.666/tools/Cli_only/cron_job >/dev/null 2>&1

which I don't really know what they do - and still don't work.

EDIT:

Just for being clear, if I run the controller on my browser, everything works perfectly!

This is all of my code in the controller, the cron_job() function is right after the __construct() function:

<?php 


class Cli_only extends CI_Controller {

    public function __construct() {

       parent::__construct();
       is_cli() OR show_404(); // If cronjob ! 
       //if (!$this->input->is_cli_request()) show_error('Direct access is not allowed');          

       $this->load->model('kas_model');

        // Sets the server not to have a time out. 
        ini_set('max_execution_time', 0); 
        ini_set('memory_limit', '-1');      
        // Expand the array displays
        ini_set('xdebug.var_display_max_depth', 5);
        ini_set('xdebug.var_display_max_children', 256);
        ini_set('xdebug.var_display_max_data', 1024);
    }



    // This function has to run every day using a corn job. 
    public function cron_job(){

        // 1. Run the query that gets the table data from the DB('from kas table')
        $data['table'] = $this->kas_model->get_kas_table();

        // 2. Go through each row.
        foreach ( $data['table'] as $row ) {

            // 3.1. But first, get vars! 
            $kas_id            = $row->kas_id;
            $kas_key       = $row->kas_key; 
            $kas_id_aaa        = $row->kas_id_aaa;
            $kas_id_bbb    = $row->kas_id_bbb;
            $kas_rank1_aaa     = $row->kas_rank1_aaa;
            $kas_rank2_aaa     = $row->kas_rank2_aaa;
            $kas_rank1_bbb = $row->kas_rank1_bbb;
            $kas_rank2_bbb = $row->kas_rank2_bbb;

            // 3.2. move to yesterday to make place for a new query result.
            $this->kas_model->move_tod_to_yes($kas_id, $kas_rank2_aaa, $kas_rank2_bbb);

            // 3.3. Run the key query again for today on each one of the keys and insert to DB. 
            if ( ($kas_id_aaa != 0) || ( !empty($kas_id_aaa) ) ) {
                $aaa_rank_today     = $this->get_rank_aaa_by_id_and_kw($kas_id_aaa, $kas_key);
            } 

            if ( ($kas_id_bbb != 0) || ( !empty($kas_id_bbb) ) ) {
                $bbb_rank_today = $this->get_rank_bbb_by_id_and_kw($kas_id_bbb, $kas_key);
            }

            // 3.4. Add the new rank to rank2 in the DB.
            $this->kas_model->add_new_today($kas_id, $aaa_rank_today, $bbb_rank_today);

            // 4. Check difference as Sag described : 
            $msg = ''; 
            $send = FALSE;
            // First if: aaa
            if ( ($aaa_rank_today > 10 ) && ( $kas_rank2_aaa < 30 ) && ( ( abs( $aaa_rank_today - $kas_rank2_aaa ) ) > 10) ) {
                $msg .= 'aaa:<br> ( (Today > 10 ) && ( Yesterday < 30 ) && ( ( |Today - Yesterday| > 10) ) ==> True. <br><br>';
                $send = TRUE;
            }

            // Second if: aaa
            if ( ( ($kas_rank2_aaa < 5) && ($aaa_rank_today > 10) ) || ( ($aaa_rank_today < 5) && ($kas_rank2_aaa > 10) ) ) {
                $msg .= 'aaa: <br>  ( ( (Yesterday < 5) && (Today > 10) ) || ( (Today < 5) && (Yesterday > 10) ) ) ==> True. <br> <br>';
                $send = TRUE;
            }

            // First if: bbb
            if ( ($bbb_rank_today > 10 ) && ( $kas_rank2_bbb < 30 ) && ( ( abs( $bbb_rank_today - $kas_rank2_bbb ) ) > 10) ) {
                $msg .= 'bbb: <br> ( (Today > 10 ) && ( Yesterday < 30 ) && ( ( |Today - Yesterday| > 10) ) ==> True. <br><br>';
                $send = TRUE;
            }

            // Second if: bbb
            if ( ( ($kas_rank2_bbb < 5) && ($bbb_rank_today > 10) ) || ( ($bbb_rank_today < 5) && ($kas_rank2_bbb > 10) ) ) {
                $msg .= 'bbb: <br> ( ( (Yesterday < 5) && (Today > 10) ) || ( (Today < 5) && (Yesterday > 10) ) ) ==> True. <br> <br>';
                $send = TRUE;
            }

            $this->send_mail($kas_id_aaa, $kas_id_bbb, $msg, $send, $aaa_rank_today, $bbb_rank_today, $kas_rank2_aaa, $kas_rank2_bbb, $kas_key);

        }



    }






    // Gets aaa categorys Ranking by ID. 
    public function get_rank_aaa_by_id_and_kw($id, $key, $query_country){

        $key_for_url = rawurlencode($key);

        $found = FALSE; 
        $i     = 0;

        // Create a stream for Json. That's how the code knows what to expect to get. 
        $context_opts = array(
            'http' => array(
            'method' => "GET",
            'header' => "Accepts: categorylication/json\r\n"
        ));
        $context = stream_context_create($context_opts); 

        while ($found == FALSE) {

            // aaa Query
            $json_query_aaa = "https://api.example.com:666/aaa/ajax/research_key?category_id=$id&term=$key_for_url&page_index=$i&country=$query_country&auth_token=tokentokentoken";
            // Get the Json
            $json_query_aaa = file_get_contents($json_query_aaa, false, $context); 
            // Turn Json to a PHP array
            $json_query_aaa = json_decode($json_query_aaa, true);
            // Finally, the main categorys array. 
            $json_query_aaa = $json_query_aaa['key']['phone_categorys']['category_list'];

            if ( count($json_query_aaa) > 2 ) {

                for ( $j=0; $j<count($json_query_aaa); $j++ ) {

                    if ( $json_query_aaa[$j]['id'] == $id ) {
                        $found = TRUE;
                        $rank  = $json_query_aaa[$j]['rank'] + 1;
                        break;
                    }

                    if ($found == TRUE){
                        break;
                    }
                }

                $i++;

            } else {

                $rank = "none"; 
                break;

            }
        }

         return $rank;
    }


    // Gets bbb categorys Ranking by ID. 
    public function get_rank_bbb_by_id_and_kw($id, $key, $query_country){

        $key_for_url = rawurlencode($key);

        $found = FALSE; 
        $i     = 0;

        // Create a stream for Json. That's how the code knows what to expect to get. 
        $context_opts = array(
            'http' => array(
            'method' => "GET",
            'header' => "Accepts: categorylication/json\r\n"
        ));
        $context = stream_context_create($context_opts); 

        while ($found == FALSE) {

            // aaa Query
            $json_query_bbb = "https://api.example.com:666/bbb/research_key?category_id=$id&term=$key_for_url&page_index=$i&country=$query_country&auth_token=tokentokentoken";
            // Get the Json
            $json_query_bbb = file_get_contents($json_query_bbb, false, $context); 
            // Turn Json to a PHP array
            $json_query_bbb = json_decode($json_query_bbb, true);
            // Finally, the main categorys array. 
            $json_query_bbb = $json_query_bbb['key']['phone_categorys']['category_list'];

            if ( count($json_query_bbb) > 2 ) {

                for ( $j=0; $j<count($json_query_bbb); $j++ ) {

                    if ( $json_query_bbb[$j]['id'] == $id ) {
                        $found = TRUE;
                        $rank  = $json_query_bbb[$j]['rank']+1;
                    }

                }

            $i++;

            } else {

                $rank = "none"; 
                break;

            }

        }

        return $rank;
    }




    // Sends to email the results 
    public function send_mail($id_aaa, $id_bbb, $msg, $send, $aaa_rank_today, $bbb_rank_today, $aaa_rank_yesterday, $bbb_rank_yesterday, $kas_key){

        if ($send) {

            $ci = get_instance();
            $config['protocol']  = "smtp";
            $config['smtp_host'] = "ssl://smtp.gmail.com";
            $config['smtp_port'] = "465";
            $config['smtp_user'] = "[email protected]"; 
            $config['smtp_pass'] = "assword";
            $config['charset']   = "utf-8";
            $config['mailtype']  = "html";
            $config['newline']   = "\r\n";
            $config['crlf']      = "\r\n";
            $config['validate']  = FALSE;

            $ci->load->library('email');
            $ci->email->initialize($config);

            $ci->email->from('[email protected]', 'key Alerting System (KAS)');
            $list = array('[email protected]', '[email protected]');
            $ci->email->to($list);
            $this->email->reply_to('[email protected]', 'KAS Alert');
            $ci->email->subject('KAS Alert!');
            $ci->email->message("key: $kas_key <br/><br/> aaa ID:$id_aaa <br> bbb ID: $id_bbb <br><br><br> $msg<br><br> aaa Rank Today: $aaa_rank_today<br> aaa Rank Yesterday: $aaa_rank_yesterday<br><br> bbb Rank Today: $bbb_rank_today<br> bbb Rank Yesterday: $bbb_rank_yesterday");
            $ci->email->send();

        } 

    }


    function test(){
        echo 'banana'; 
    }


}

EDIT #2:

This works fine when not having is_cli() OR show_404(); in the construct function. But I do want this controller to work only from a cronjob

I get the same result with:

if (!$this->input->is_cli_request()) show_error('Direct access is not allowed');

like image 742
Imnotapotato Avatar asked Dec 06 '15 14:12

Imnotapotato


2 Answers

curl -O - http://10.0.1.666/tools/Cli_only/cron_job >/dev/null 2>&1 is not cli. Curl makes normal http request to your webserver, whilst cli stands for php command line script.

To run it as cli:

$ cd /path/to/your/web/root
$ php index.php tools Cli_only cron_job

For your conjob it must be:

14 16 * * *  cd /path/to/project; php tools Cli_only cron_job >/dev/null 2>&1

EDIT

It is quite common practice to run curl requests from cron job, which have it's pros. For example it allows to run a cron job as any user, and guarantee the job is executed by webserver user. Using cli, it is your responsibility to set the cron job for correct user, e.g. crontab -u www-data -e if your webserver user is www-data. Otherwise you are at risk to mess with permissions for temporary files like caches, logs etc.

If you are not sure about internals, it may be better to keep using curl in your cron job, but limit access to the controller for certain IP addresses. For example instead of

is_cli() OR show_404();

use something like

$this->input->ip_address() == '127.0.0.1' OR show_404();
like image 106
Alex Blex Avatar answered Nov 18 '22 22:11

Alex Blex


First I don't understand why you running a crotab through a http request. You can absolutely run a crontab on your server which is 10.0.1.666,which can also proceed if there is something wrong with the internet. Besides you said 'This works fine when not having is_cli() OR show_404();' ,that because In the crontab you are writing send an http request. Suppose you are the client ,And the server is 10.0.1.666. EACH TIME as the crontab is running ,the 'client' send a http request. And the server 666 receives the request then excute the controller you wrote. It's not a cli script. If you insist doing this by sending http request. I have 2 adivices(not best but may working)

  1. Add some GET parameter which only you know like http://10.0.1.666/tools/Cli_only/cron_job?running=no_one_knows_this
  2. change your controller get the para running ,if the para isnot 'no_one_knows_this' , exit();

Second ,I strongly suggest you run the bash on the server .

like image 32
Huck c Avatar answered Nov 18 '22 21:11

Huck c