root/404-notifier/trunk/404-notifier.php

Revision 37080, 10.6 kB (checked in by alexkingorg, 3 months ago)

removing debug msg

Line 
1 <?php
2
3 /*
4 Plugin Name: 404 Notifier
5 Plugin URI: http://alexking.org/projects/wordpress
6 Description: This plugin will log 404 hits on your site and can notify you via e-mail or you can subscribe to the generated RSS feed of 404 events. Adjust your settings <a href="options-general.php?page=404-notifier.php">here</a>.
7 Version: 1.2a
8 Author: Alex King
9 Author URI: http://alexking.org
10 */
11
12 // Copyright (c) 2006-2008 Alex King. All rights reserved.
13 // http://alexking.org/projects/wordpress
14 //
15 // Released under the GPL license
16 // http://www.opensource.org/licenses/gpl-license.php
17 //
18 // This is an add-on for WordPress
19 // http://wordpress.org/
20 //
21 // **********************************************************************
22 // This program is distributed in the hope that it will be useful, but
23 // WITHOUT ANY WARRANTY; without even the implied warranty of
24 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
25 // **********************************************************************
26
27 load_plugin_textdomain('404-notifier');
28
29 $_SERVER['REQUEST_URI'] = ( isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_SERVER['SCRIPT_NAME'] . (( isset($_SERVER['QUERY_STRING']) ? '?' . $_SERVER['QUERY_STRING'] : '')));
30
31 class ak_404 {
32     var $url_404;
33     var $url_refer;
34     var $user_agent;
35     var $mailto;
36     var $mail_enabled;
37     var $rss_limit;
38     var $options;
39     
40     function ak_404() {
41         if (isset($_SERVER['REQUEST_URI'])) {
42             $this->url_404 = 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI'];
43         }
44         else {
45             $this->url_404 = '';
46         }
47         if (isset($_SERVER['HTTP_REFERER'])) {
48             $this->url_refer = $_SERVER['HTTP_REFERER'];
49         }
50         else {
51             $this->url_refer = '';
52         }
53         if (isset($_SERVER['HTTP_USER_AGENT'])) {
54             $this->user_agent = $_SERVER['HTTP_USER_AGENT'];
55         }
56         else {
57             $this->user_agent = '';
58         }
59         $this->mailto = '';
60         $this->mail_enabled = 0;
61         $this->rss_limit = 100;
62         $this->options = array(
63             'mailto' => 'email'
64             , 'mail_enabled' => 'int'
65             , 'rss_limit' => 'int'
66         );
67     }
68     
69     function install() {
70         global $wpdb;
71         $result = $wpdb->query("
72             CREATE TABLE `$wpdb->ak_404_log` (
73             `id` INT( 11 ) NOT NULL AUTO_INCREMENT PRIMARY KEY ,
74             `url_404` TEXT NOT NULL ,
75             `url_refer` TEXT NULL ,
76             `user_agent` TEXT NULL ,
77             `date_gmt` DATETIME NOT NULL
78             )
79         ");
80         add_option('ak404_mailto', $this->mailto, 'Address to send mail to.');
81         add_option('ak404_mail_enabled', $this->mail_enabled, 'Send mail notifications?');
82         add_option('ak404_rss_limit', $this->rss_limit, '# of items to show at once in RSS Feed');
83     }
84     
85     function update_settings() {
86         foreach ($this->options as $option => $type) {
87             if (isset($_POST[$option])) {
88                 switch ($type) {
89                     case 'email':
90                         $value = stripslashes($_POST[$option]);
91                         if (!ak_check_email_address($value)) {
92                             $value = '';
93                         }
94                         break;
95                     case 'int':
96                         $value = intval($_POST[$option]);
97                         break;
98                     default:
99                         $value = stripslashes($_POST[$option]);
100                 }
101                 update_option('ak404_'.$option, $value);
102             }
103             else {
104                 update_option('ak404_'.$option, $this->$option);
105             }
106         }
107
108         header('Location: '.get_bloginfo('wpurl').'/wp-admin/options-general.php?page=404-notifier.php&updated=true');
109         die();
110     }
111     
112     function get_settings() {
113         foreach ($this->options as $option => $type) {
114             $this->$option = get_option('ak404_'.$option);
115             switch ($type) {
116                 case 'email':
117                     $this->$option = $this->$option;
118                     break;
119                 case 'int':
120                     $this->$option = intval($this->$option);
121                     break;
122             }
123         }
124     }
125     
126     function log_404() {
127         global $wpdb;
128         if (empty($this->url_404)) {
129             return;
130         }
131         $wpdb->query("
132             INSERT INTO $wpdb->ak_404_log
133             ( url_404
134             , url_refer
135             , user_agent
136             , date_gmt
137             )
138             VALUES
139             ( '".mysql_real_escape_string($this->url_404)."'
140             , '".mysql_real_escape_string($this->url_refer)."'
141             , '".mysql_real_escape_string($this->user_agent)."'
142             , '".current_time('mysql',1)."'
143             )
144         ");
145         $this->mail_404();
146     }
147     
148     function mail_404() {
149         if (!empty($this->mailto) && $this->mail_enabled) {
150             $to      = $this->mailto;
151             $subject = '404: '.$this->url_404;
152             $message = '404 Report - a file not found error was registered on your site.'."\n\n"
153                 .'404 URL:     '.$this->url_404."\n\n"
154                 .'Referred by: '.$this->url_refer."\n\n"
155                 .'User Agent: '.$this->user_agent."\n\n";
156             $headers = 'From: '.$this->mailto . "\r\n"
157                 .'Reply-To: '.$this->mailto . "\r\n"
158                 .'X-Mailer: PHP/' . phpversion();
159             
160             mail($to, $subject, $message, $headers);
161         }
162     }
163
164     function options_form() {
165         switch ($this->mail_enabled) {
166             case '1':
167                 $enabled = ' checked="checked"';
168                 break;
169             case '0':
170                 $enabled = '';
171                 break;
172         }
173         print('
174             <div class="wrap">
175                 <h2>'.__('404 Notifier Options', '404-notifier').'</h2>
176                 <form name="ak_404" action="'.get_bloginfo('wpurl').'/wp-admin/options-general.php" method="post">
177                     <fieldset class="options">
178                         <p>
179                             <input type="checkbox" name="mail_enabled" id="ak404_mail_enabled" value="1" '.$enabled.'/>
180                             <label for="ak404_mail_enabled">'.__('Enable mail notifications on 404 hits.', '404-notifier').'</label>
181                         </p>
182                         <p>
183                             <label for="mailto">'.__('E-mail address to notify:', '404-notifier').'</label>
184                             <input type="text" size="35" name="mailto" id="mailto" value="'.htmlspecialchars($this->mailto).'" />
185                         </p>
186                         <p>
187                             <label for="rss_limit">'.__('Limit the RSS Feed to how many items?', '404-notifier').'</label>
188                             <input type="text" size="5" name="rss_limit" id="rss_limit" value="'.intval($this->rss_limit).'" />
189                         </p>
190                         <p><a href="'.get_bloginfo('wpurl').'/wp-admin/options-general.php?ak_action=404_feed">'.__('RSS Feed of 404 Events', '404-notifier').'</a></p>
191                         <input type="hidden" name="ak_action" value="update_404_settings" />
192                     </fieldset>
193                     <p class="submit">
194                         <input type="submit" name="submit" value="'.__('Update 404 Notifier Settings', '404-notifier').'" />
195                     </p>
196                 </form>
197             </div>
198         ');
199     }
200     
201     function rss_feed() {
202         global $wpdb;
203         $events = $wpdb->get_results("
204             SELECT *
205             FROM $wpdb->ak_404_log
206             ORDER BY date_gmt DESC
207             LIMIT $this->rss_limit
208         ");
209         header('Content-type: text/xml; charset=' . get_option('blog_charset'), true);
210         echo '<?xml version="1.0" encoding="'.get_option('blog_charset').'"?'.'>';
211 ?>
212 <rss version="2.0"
213     xmlns:content="http://purl.org/rss/1.0/modules/content/"
214     xmlns:wfw="http://wellformedweb.org/CommentAPI/"
215     xmlns:dc="http://purl.org/dc/elements/1.1/"
216 >
217
218 <channel>
219     <title><?php print(__('404 Report for: ', '404-notifier')); bloginfo_rss('name'); ?></title>
220     <link><?php bloginfo_rss('url') ?></link>
221     <description><?php bloginfo_rss("description") ?></description>
222     <pubDate><?php echo mysql2date('D, d M Y H:i:s +0000', get_lastpostmodified('GMT'), false); ?></pubDate>
223     <generator>http://wordpress.org/?v=<?php bloginfo_rss('version'); ?></generator>
224     <language><?php echo get_option('rss_language'); ?></language>
225 <?php
226         if (count($events) > 0) {
227             foreach ($events as $event) {
228                 $content = '
229                     <p>'.__('404 URL: ', '404-notifier').'<a href="'.$event->url_404.'">'.$event->url_404.'</a></p>
230                     <p>'.__('Referring URL: ', '404-notifier').'<a href="'.$event->url_refer.'">'.$event->url_refer.'</a></p>
231                     <p>'.__('User Agent: ', '404-notifier').$event->user_agent.'</p>
232                 ';
233 ?>
234     <item>
235         <title><![CDATA[<?php print('404: '.htmlspecialchars($event->url_404)); ?>]]></title>
236         <link><![CDATA[<?php print($event->url_404); ?>]]></link>
237         <pubDate><?php echo mysql2date('D, d M Y H:i:s +0000', $event->date_gmt, false); ?></pubDate>
238         <guid isPermaLink="false"><?php print($event->id); ?></guid>
239         <description><![CDATA[<?php print($content); ?>]]></description>
240         <content:encoded><![CDATA[<?php print($content); ?>]]></content:encoded>
241     </item>
242 <?php $items_count++; if (($items_count == get_option('posts_per_rss')) && !is_date()) { break; } } } ?>
243 </channel>
244 </rss>
245 <?php
246         die();
247     }
248 }
249
250 if (!function_exists('ak_check_email_address')) {
251     function ak_check_email_address($email) {
252 // From: http://www.ilovejackdaniels.com/php/email-address-validation/
253 // First, we check that there's one @ symbol, and that the lengths are right
254         if (!ereg("^[^@]{1,64}@[^@]{1,255}$", $email)) {
255             // Email invalid because wrong number of characters in one section, or wrong number of @ symbols.
256             return false;
257         }
258 // Split it into sections to make life easier
259         $email_array = explode("@", $email);
260         $local_array = explode(".", $email_array[0]);
261         for ($i = 0; $i < sizeof($local_array); $i++) {
262              if (!ereg("^(([A-Za-z0-9!#$%&'*+/=?^_`{|}~-][A-Za-z0-9!#$%&'*+/=?^_`{|}~\.-]{0,63})|(\"[^(\\|\")]{0,62}\"))$", $local_array[$i])) {
263                 return false;
264             }
265         }   
266         if (!ereg("^\[?[0-9\.]+\]?$", $email_array[1])) { // Check if domain is IP. If not, it should be valid domain name
267             $domain_array = explode(".", $email_array[1]);
268             if (sizeof($domain_array) < 2) {
269                     return false; // Not enough parts to domain
270             }
271             for ($i = 0; $i < sizeof($domain_array); $i++) {
272                 if (!ereg("^(([A-Za-z0-9][A-Za-z0-9-]{0,61}[A-Za-z0-9])|([A-Za-z0-9]+))$", $domain_array[$i])) {
273                     return false;
274                 }
275             }
276         }
277         return true;
278     }
279 }
280
281 function ak404_log() {
282     if (is_404()) {
283         global $ak404;
284         $ak404->log_404();
285     }
286 }
287 add_action('shutdown', 'ak404_log');
288
289 function ak404_options() {
290     if (function_exists('add_options_page')) {
291         add_options_page(
292             __('404 Notifier Options', '404-notifier')
293             , __('404 Notifier', '404-notifier')
294             , 10
295             , basename(__FILE__)
296             , 'ak404_options_form'
297         );
298     }
299 }
300 add_action('admin_menu', 'ak404_options');
301
302 function ak404_options_form() {
303     global $ak404;
304     $ak404->options_form();
305 }
306
307 function ak404_request_handler() {
308     $ak404 = new ak_404;
309     if (!empty($_POST['ak_action'])) {
310         switch($_POST['ak_action']) {
311             case 'update_404_settings':
312                 $ak404->update_settings();
313                 break;
314         }
315     }
316     if (!empty($_GET['ak_action'])) {
317         switch($_GET['ak_action']) {
318             case '404_feed':
319                 $ak404->rss_feed();
320                 break;
321         }
322     }
323 }
324 add_action('init', 'ak404_request_handler', 99);
325
326 function ak404_init() {
327     global $ak404, $wpdb;
328     $ak404 = new ak_404;
329     $wpdb->ak_404_log = $wpdb->prefix.'ak_404_log';
330     // CHECK FOR 404 NOTIFIER TABLES
331     if (isset($_GET['activate']) && $_GET['activate'] == 'true') {
332         $result = mysql_list_tables(DB_NAME);
333         $tables = array();
334         while ($row = mysql_fetch_row($result)) {
335             $tables[] = $row[0];
336         }
337         if (!in_array($wpdb->ak_404_log, $tables)) {
338             $ak404->install();
339         }
340     }
341     $ak404->get_settings();
342 }
343 add_action('init', 'ak404_init');
344
345 function ak404_admin_head() {
346     global $wp_version;
347     if (isset($wp_version) && version_compare($wp_version, '2.5', '>=')) {
348         print('
349 <style type="text/css">
350 fieldset.options {
351     border: 0;
352     padding: 10px;
353 }
354 fieldset.options p {
355     margin-bottom: 10px;
356 }
357 </style>
358         ');
359     }
360 }
361 add_action('admin_head', 'ak404_admin_head');
362
363 ?>
Note: See TracBrowser for help on using the browser.