2 if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3 /*********************************************************************************
4 * SugarCRM Community Edition is a customer relationship management program developed by
5 * SugarCRM, Inc. Copyright (C) 2004-2012 SugarCRM Inc.
7 * This program is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU Affero General Public License version 3 as published by the
9 * Free Software Foundation with the addition of the following permission added
10 * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
11 * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
12 * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
14 * This program is distributed in the hope that it will be useful, but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16 * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
19 * You should have received a copy of the GNU Affero General Public License along with
20 * this program; if not, see http://www.gnu.org/licenses or write to the Free
21 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
24 * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
25 * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
27 * The interactive user interfaces in modified source and object code versions
28 * of this program must display Appropriate Legal Notices, as required under
29 * Section 5 of the GNU Affero General Public License version 3.
31 * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
32 * these Appropriate Legal Notices must retain the display of the "Powered by
33 * SugarCRM" logo. If the display of the logo is not reasonably feasible for
34 * technical reasons, the Appropriate Legal Notices must display the words
35 * "Powered by SugarCRM".
36 ********************************************************************************/
41 class SchedulersJob extends SugarBean {
45 var $date_entered = '';
46 var $date_modified = '';
47 var $scheduler_id = '';
48 var $execute_time = '';
50 // standard SugarBean child attrs
51 var $table_name = "schedulers_times";
52 var $object_name = "SchedulersJob";
53 var $module_dir = "SchedulersJobs";
54 var $new_schema = true;
55 var $process_save_dates = true;
57 var $job_name; // the Scheduler's 'name' field
58 var $job; // the Scheduler's 'job' field
59 // object specific attributes
60 var $user; // User object
61 var $scheduler; // Scheduler parent
66 function SchedulersJob($init=true) {
70 //check is default admin exists
71 $adminId = $this->db->getOne(
72 'SELECT id FROM users WHERE id='.$this->db->quoted('1').' AND is_admin=1 AND deleted=0 AND status='.$this->db->quoted('Active'),
74 'Error retrieving Admin account info'
76 if (false === $adminId) {//retrive other admin
77 $adminId = $this->db->getOne(
78 'SELECT id FROM users WHERE is_admin=1 AND deleted=0 AND status='.$this->db->quoted('Active'),
80 'Error retrieving Admin account info'
83 $user->retrieve($adminId);
85 $GLOBALS['log']->fatal('No Admin account found!');
90 $user->retrieve('1'); // Scheduler jobs run as default Admin
97 ///////////////////////////////////////////////////////////////////////////
98 //// SCHEDULERSJOB HELPER FUNCTIONS
100 function fireSelf($id) {
102 $sched = new Scheduler();
103 $sched->retrieve($id);
105 $exJob = explode('::', $sched->job);
107 if(is_array($exJob)) {
108 $this->scheduler_id = $sched->id;
109 $this->scheduler = $sched;
110 $this->execute_time = $this->handleDateFormat('now');
113 if($exJob[0] == 'function') {
114 $GLOBALS['log']->debug('----->Scheduler found a job of type FUNCTION');
115 require_once('modules/Schedulers/_AddJobsHere.php');
117 $this->setJobFlag(1);
120 $GLOBALS['log']->debug('----->SchedulersJob firing '.$func);
122 $res = call_user_func($func);
124 $this->setJobFlag(2);
128 $this->setJobFlag(3);
131 } elseif($exJob[0] == 'url') {
132 if(function_exists('curl_init')) {
133 $GLOBALS['log']->debug('----->SchedulersJob found a job of type URL');
134 $this->setJobFlag(1);
136 $GLOBALS['log']->debug('----->SchedulersJob firing URL job: '.$exJob[1]);
137 if($this->fireUrl($exJob[1])) {
138 $this->setJobFlag(2);
142 $this->setJobFlag(3);
146 $this->setJobFlag(4);
157 * This function handles returning a datetime value. It allows a user instance to be passed in, but will default to the
158 * user member variable instance if none is found.
160 * @param string $date String value of the date to calculate, defaults to 'now'
161 * @param object $user The User instance to use in calculating the time value, if empty, it will default to user member variable
162 * @param boolean $user_format Boolean indicating whether or not to convert to user's time format, defaults to false
164 * @return string Formatted datetime value
166 function handleDateFormat($date='now', $user=null, $user_format=false) {
169 if(!isset($timedate) || empty($timedate))
171 $timedate = new TimeDate();
174 // get user for calculation
175 $user = (empty($user)) ? $this->user : $user;
179 $dbTime = $timedate->asUser($timedate->getNow(), $user);
181 $dbTime = $timedate->asUser($timedate->fromString($date, $user), $user);
184 // if $user_format is set to true then just return as th user's time format, otherwise, return as database format
185 return $user_format ? $dbTime : $timedate->fromUser($dbTime, $user)->asDb();
188 function setJobFlag($flag) {
189 $trackerManager = TrackerManager::getInstance();
190 $trackerManager->pause();
191 $status = array (0 => 'ready', 1 => 'in progress', 2 => 'completed', 3 => 'failed', 4 => 'no curl');
192 $statusScheduler = array (0 => 'Active', 1 => 'In Progress', 2 => 'Active', 3 => 'Active', 4 => 'Active');
193 $GLOBALS['log']->info('-----> SchedulersJob setting Job flag: '.$status[$flag].' AND setting Scheduler status to: '.$statusScheduler[$flag]);
195 $time = $this->handleDateFormat('now');
196 $this->status = $status[$flag];
197 $this->scheduler->retrieve($this->scheduler_id);
198 $this->scheduler->status = $statusScheduler[$flag];
199 $this->scheduler->save();
201 $this->retrieve($this->id);
202 $trackerManager->unPause();
206 * This function takes a job_id, and updates schedulers last_run as well as
207 * soft delete the job instance from schedulers_times
208 * @return boolean Success
210 function finishJob() {
211 $trackerManager = TrackerManager::getInstance();
212 $trackerManager->pause();
213 $GLOBALS['log']->debug('----->SchedulersJob updating Job Status and finishing Job execution.');
214 $this->scheduler->retrieve($this->scheduler->id);
215 $this->scheduler->last_run = gmdate($GLOBALS['timedate']->get_db_date_time_format());
216 if($this->scheduler->last_run == gmdate($GLOBALS['timedate']->get_db_date_time_format(), strtotime('Jan 01 2000 00:00:00'))) {
217 $this->scheduler->last_run = $this->handleDateFormat('now');
218 $GLOBALS['log']->fatal('Scheduler applying bogus date for "Last Run": '.$this->scheduler->last_run);
220 $this->scheduler->save();
221 $trackerManager->unPause();
225 * This function takes a passed URL and cURLs it to fake multi-threading with another httpd instance
226 * @param $job String in URI-clean format
227 * @param $timeout Int value in secs for cURL to timeout. 30 default.
229 //TODO: figure out what error is thrown when no more apache instances can be spun off
230 function fireUrl($job, $timeout=30) {
233 curl_setopt($ch, CURLOPT_URL, $job); // set url
234 curl_setopt($ch, CURLOPT_FAILONERROR, true); // silent failure (code >300);
235 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); // do not follow location(); inits - we always use the current
236 curl_setopt($ch, CURLOPT_FORBID_REUSE, 1);
237 curl_setopt($ch, CURLOPT_DNS_USE_GLOBAL_CACHE, false); // not thread-safe
238 curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // return into a variable to continue program execution
239 curl_setopt($ch, CURLOPT_TIMEOUT, $timeout); // never times out - bad idea?
240 curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5); // 5 secs for connect timeout
241 curl_setopt($ch, CURLOPT_FRESH_CONNECT, true); // open brand new conn
242 curl_setopt($ch, CURLOPT_HEADER, true); // do not return header info with result
243 curl_setopt($ch, CURLOPT_NOPROGRESS, true); // do not have progress bar
244 $urlparts = parse_url($job);
245 if(empty($urlparts['port'])) {
246 if($urlparts['scheme'] == 'https'){
247 $urlparts['port'] = 443;
249 $urlparts['port'] = 80;
252 curl_setopt($ch, CURLOPT_PORT, $urlparts['port']); // set port as reported by Server
253 //TODO make the below configurable
254 curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); // most customers will not have Certificate Authority account
255 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // most customers will not have Certificate Authority account
257 if(constant('PHP_VERSION') > '5.0.0') {
258 curl_setopt($ch, CURLOPT_NOSIGNAL, true); // ignore any cURL signals to PHP (for multi-threading)
260 $result = curl_exec($ch);
261 $cInfo = curl_getinfo($ch); //url,content_type,header_size,request_size,filetime,http_code
262 //ssl_verify_result,total_time,namelookup_time,connect_time
263 //pretransfer_time,size_upload,size_download,speed_download,
264 //speed_upload,download_content_length,upload_content_length
265 //starttransfer_time,redirect_time
268 if($result !== FALSE && $cInfo['http_code'] < 400) {
269 $GLOBALS['log']->debug('----->Firing was successful: ('.$job.') at '.$this->handleDateFormat('now'));
270 $GLOBALS['log']->debug('----->WTIH RESULT: '.strip_tags($result).' AND '.strip_tags(print_r($cInfo, true)));
273 $GLOBALS['log']->fatal('Job errored: ('.$job.') at '.$this->handleDateFormat('now'));
277 //// END SCHEDULERSJOB HELPER FUNCTIONS
278 ///////////////////////////////////////////////////////////////////////////
281 ///////////////////////////////////////////////////////////////////////////
282 //// STANDARD SUGARBEAN OVERRIDES
284 * This function gets DB data and preps it for ListViews
286 function get_list_view_data(){
289 $temp_array = $this->get_list_view_array();
290 $temp_array['JOB_NAME'] = $this->job_name;
291 $temp_array['JOB'] = $this->job;
296 /** method stub for future customization
299 function fill_in_additional_list_fields() {
300 $this->fill_in_additional_detail_fields();
303 function fill_in_additional_detail_fields() {
304 // get the Job Name and Job fields from schedulers table
305 // $q = "SELECT name, job FROM schedulers WHERE id = '".$this->job_id."'";
306 // $result = $this->db->query($q);
307 // $row = $this->db->fetchByAssoc($result);
308 // $this->job_name = $row['name'];
309 // $this->job = $row['job'];
310 // $GLOBALS['log']->info('Assigned Name('.$this->job_name.') and Job('.$this->job.') to Job');
312 // $this->created_by_name = get_assigned_user_name($this->created_by);
313 // $this->modified_by_name = get_assigned_user_name($this->modified_user_id);
318 * returns the bean name - overrides SugarBean's
320 function get_summary_text() {
321 if(isset($this->name))
326 * function overrides the one in SugarBean.php