getOptions(true); return (@$options['debug_mode'] == true); } /** Send a message to the error_log if debug mode is on. * This goes to a file and is used by every other class so it goes here. * @param type $message */ function debugMessage($message) { if ($this->isDebug()) { $prefix = "ABJ-404-SOLUTION (DEBUG): "; $timestamp = date('Y-m-d H:i:s T') . ' (DEBUG): '; error_log($prefix . $message); $this->writeLineToDebugFile($timestamp . $message); } } /** Send a message to the log. * This goes to a file and is used by every other class so it goes here. * @param type $message */ function infoMessage($message) { $timestamp = date('Y-m-d H:i:s T') . ' (INFO): '; $this->writeLineToDebugFile($timestamp . $message); } /** Always send a message to the error_log. * This goes to a file and is used by every other class so it goes here. * @param type $message * @param Exception $e */ function errorMessage($message, $e = null) { if ($e == null) { $e = new Exception; } $stacktrace = $e->getTraceAsString(); $prefix = "ABJ-404-SOLUTION (ERROR): "; $timestamp = date('Y-m-d H:i:s T') . ' (ERROR): '; $referrer = ''; if (array_key_exists('HTTP_REFERER', $_SERVER) && !empty($_SERVER['HTTP_REFERER'])) { $referrer = $_SERVER['HTTP_REFERER']; } error_log($prefix . $message); $this->writeLineToDebugFile($timestamp . $message . ", PHP version: " . PHP_VERSION . ", WP ver: " . get_bloginfo('version') . ", Plugin ver: " . ABJ404_VERSION . ", Referrer: " . esc_html($referrer) . ", \nTrace: " . $stacktrace); // display a 404 page if the user is NOT an admin and is not on an admin page. if (!is_admin() && !current_user_can('administrator')) { // send the user to a 404 page. otherwise the user might just get a blank page. status_header(404); nocache_headers(); include(get_query_template('404')); exit(); } } /** Log the user capabilities. * @param type $msg */ function logUserCapabilities($msg) { $user = wp_get_current_user(); $usercaps = str_replace(',"', ', "', wp_kses_post(json_encode($user->get_role_caps()))); $this->debugMessage("User caps msg: " . esc_html($msg == '' ? '(none)' : $msg) . ", is_admin(): " . is_admin() . ", current_user_can('administrator'): " . current_user_can('administrator') . ", user caps: " . wp_kses_post(json_encode($user->caps)) . ", get_role_caps: " . $usercaps . ", WP ver: " . get_bloginfo('version')); } /** Write the line to the debug file. * @param type $line */ function writeLineToDebugFile($line) { file_put_contents($this->getDebugFilePath(), $line . "\n", FILE_APPEND); } /** Email the log file to the plugin developer. */ function emailErrorLogIfNecessary() { if (!file_exists($this->getDebugFilePath())) { $this->debugMessage("No log file found so no errors were found."); return false; } // get the number of the last line with an error message. $latestErrorLineFound = $this->getLatestErrorLine(); // if no error was found then we're done. if ($latestErrorLineFound['num'] == -1) { $this->debugMessage("No errors found in the log file."); return false; } // ------------------- // get/check the last line that was emailed to the admin. $sentDateFile = $this->getDebugFilePathSentFile(); if (file_exists($sentDateFile)) { $sentLine = absint(ABJ_404_Solution_Functions::readFileContents($sentDateFile)); } else { $sentLine = -1; } // if we already sent the error line then don't send the log file again. if ($latestErrorLineFound['num'] <= $sentLine) { $this->debugMessage("The latest error line from the log file was already emailed. " . $latestErrorLineFound['num'] . ' <= ' . $sentLine); return false; } // only email the error file if the latest version of the plugin is installed. if (!$this->latestVersionIsInstalled()) { return false; } $this->emailLogFileToDeveloper($latestErrorLineFound['line']); // update the latest error line emailed to the developer. file_put_contents($sentDateFile, $latestErrorLineFound['num']); return true; } /** Check wordpress.org for the latest version of this plugin. Return true if the latest version is installed, * false otherwise. * @return boolean */ function latestVersionIsInstalled() { if (!function_exists('plugins_api')) { require_once(ABSPATH . 'wp-admin/includes/plugin-install.php'); } if (!function_exists('plugins_api')) { $this->debugMessage("I couldn't find the plugins_api function to check for the latest version, " . "so I won't be emailing the error file."); return false; } $pluginSlug = dirname(ABJ404_NAME); // set the arguments to get latest info from repository via API ## $args = array( 'slug' => $pluginSlug, 'fields' => array( 'version' => true, ) ); /** Prepare our query */ $call_api = plugins_api('plugin_information', $args); /** Check for Errors & Display the results */ if (is_wp_error($call_api)) { $api_error = $call_api->get_error_message(); $this->debugMessage("There was an API issue checking the latest plugin version, " . "so I won't be emailing the error file. (" . esc_html($api_error) . ")"); return false; } $version_latest = $call_api->version; if (ABJ404_VERSION == $version_latest) { return true; } return false; } function emailLogFileToDeveloper($errorLineMessage) { // email the log file. $this->debugMessage("Creating zip file of error log file."); $logFileZip = $this->getZipFilePath(); if (file_exists($logFileZip)) { ABJ_404_Solution_Functions::safeUnlink($logFileZip); } $zip = new ZipArchive; if ($zip->open($logFileZip, ZipArchive::CREATE) === TRUE) { $zip->addFile($this->getDebugFilePath(), basename($this->getDebugFilePath())); $zip->close(); } $attachments = array(); $attachments[] = $logFileZip; $to = ABJ404_AUTHOR_EMAIL; $subject = ABJ404_PP . ' error log file. Plugin version: ' . ABJ404_VERSION; $body = $subject . "\nSent " . date('Y/m/d h:i:s T') . "

\n\n" . "PHP version: " . PHP_VERSION . ",
\nWordPress version: " . get_bloginfo('version') . ",
\nPlugin version: " . ABJ404_VERSION . "
\nError: " . $errorLineMessage; $headers = array('Content-Type: text/html; charset=UTF-8'); $headers[] = 'From: ' . get_option('admin_email'); // send the email $this->debugMessage("Sending error log zip file as attachment."); wp_mail($to, $subject, $body, $headers, $attachments); // delete the zip file. $this->debugMessage("Mail sent. Deleting error log zip file."); ABJ_404_Solution_Functions::safeUnlink($logFileZip); } /** * @return int */ function getLatestErrorLine() { $latestErrorLineFound = array(); $latestErrorLineFound['num'] = -1; $latestErrorLineFound['line'] = null; $linesRead = 0; $handle = null; try { if ($handle = fopen($this->getDebugFilePath(), "r")) { // read the file one line at a time. while (($line = fgets($handle)) !== false) { $linesRead++; // if the line has an error then save the line number. if (stripos($line, '(ERROR)') !== false) { $latestErrorLineFound['num'] = $linesRead; $latestErrorLineFound['line'] = $line; } } } else { $this->errorMessage("Error reading log file (1).", $e); } } catch (Exception $e) { $this->errorMessage("Error reading log file. (2)", $e); } if ($handle != null) { fclose($handle); } return $latestErrorLineFound; } /** Return the path to the debug file. * @return type */ function getDebugFilePath() { return $this->getFilePathAndMoveOldFile(ABJ404_PATH . 'temp/', 'abj404_debug.txt'); } /** Return the path to the file that stores the latest error line in the log file. * @return type */ function getDebugFilePathSentFile() { return $this->getFilePathAndMoveOldFile(ABJ404_PATH . 'temp/', 'abj404_debug_sent_line.txt'); } /** Return the path to the zip file for sending the debug file. * @return type */ function getZipFilePath() { return $this->getFilePathAndMoveOldFile(ABJ404_PATH . 'temp/', 'abj404_debug.zip'); } function getFilePathAndMoveOldFile($directory, $filename) { // create the directory and move the file if (!$this->createDirectoryWithErrorMessages($directory)) { return ABJ404_PATH . $filename; } if (file_exists(ABJ404_PATH . $filename)) { // move the file to the new location rename(ABJ404_PATH . $filename, $directory . $filename); } return $directory . $filename; } /** * @param type $directory * @return boolean */ function createDirectoryWithErrorMessages($directory) { if (!is_dir($directory)) { if (file_exists(rtrim($directory, '/'))) { error_log("ABJ-404-SOLUTION (ERROR) " . date('Y-m-d H:i:s T') . ": Error creating the directory " . $directory . ". A file with that name alraedy exists."); return false; } else if (!mkdir($directory)) { error_log("ABJ-404-SOLUTION (ERROR) " . date('Y-m-d H:i:s T') . ": Error creating the directory " . $directory . ". Unknown issue."); return false; } } return true; } /** * @return type true if the file was deleted. */ function deleteDebugFile() { // since the debug file is being deleted we reset the last error line that was sent. if (file_exists($this->getDebugFilePathSentFile())) { ABJ_404_Solution_Functions::safeUnlink($this->getDebugFilePathSentFile()); } if (!file_exists($this->getDebugFilePath())) { return true; } return ABJ_404_Solution_Functions::safeUnlink($this->getDebugFilePath()); } /** * @return int file size in bytes */ function getDebugFileSize() { if (!file_exists($this->getDebugFilePath())) { return 0; } return filesize($this->getDebugFilePath()); } }