Codeigniter 404 errors - How to tell where they're coming from? - codeigniter

For example in my logs I have many lines that repeat, such as:
ERROR - 2011-07-06 09:19:01 --> 404 Page Not Found --> favicon.ico
Is there any way for me to find out who is calling these errant URLs? The favicon is just an example, there are some URLs that for example show an intent to hack, and others it's just the same error repeated over and over and over again. Basically I'd love to know which IP's to potentially block as well as what sites to contact if they have bad links (or if I should just redirect them on my server with .htaccess).

If you feel the need to do this, just extend the Exceptions class and override the show_404() function:
// v2.x: core/MY_Exceptions.php
// v1.x: libraries/MY_Exceptions.php
class MY_Exceptions extends CI_Exceptions {
/**
* 404 Page Not Found Handler
*
* #access private
* #param string
* #return string
*/
function show_404($page = '', $log_error = TRUE)
{
$heading = "404 Page Not Found";
$message = "The page you requested was not found.";
// By default we log this, but allow a dev to skip it
if ($log_error)
{
// Custom code here, maybe logging some $_SERVER variables
// $_SERVER['HTTP_REFERER'] or $_SERVER['REMOTE_ADDR'] perhaps
// Just add whatever you want to the log message
log_message('error', '404 Page Not Found --> '.$page);
}
echo $this->show_error($heading, $message, 'error_404', 404);
exit;
}
}
If you keep getting stuff like favicon.ico, there's a good chance this is your fault, so you might want to look into that.
Just to clarify:
$_SERVER['HTTP_REFERER'] will give you the URL the page was requested from, so you can see where the request originated, whether it be on your site or elsewhere.
$_SERVER['REMOTE_ADDR'] should give you the IP address the request was made by
http://php.net/manual/en/reserved.variables.server.php
Brief Example:
if ($log_error)
{
$msg = '';
if (isset($_SERVER['HTTP_REFERER']))
{
$msg .= 'Referer was '.$_SERVER['HTTP_REFERER'];
}
else
{
$msg .= 'Referer was not set or empty';
}
if (isset($_SERVER['REMOTE_ADDR']))
{
$msg .= 'IP address was '.$_SERVER['REMOTE_ADDR'];
}
else
{
$msg .= 'Unable to track IP';
}
log_message('error', '404 Page Not Found --> '.$page.' - '.$msg);
}

I believe if you want this, you'd have to log it yourself by creating a custom 404 page and manually logging to the log file. You can access the IP address in PHP via $_SERVER['REMOTE_ADDR'].

Related

CodeIgniter, set_flashdata not working after redirect

set_flashdata is not working directly after redirect with only one redirect.
I am using one controller in this process - Profilers' Controller. It handles the member confirmation process and also displays the login page on the redirect. The process is as follows:
this session set_flashdata ('topic', 'newmember')
redirect ('login')
route ['login'] = 'profilers/signIn'
topic = $this session flashdata ('topic')
I have turned off all database session configuration for cleaner debugging and even though session library is turned on in configs, I have started calling it anyways which doesn't seem to work either.
Here is my code. As you can see, I am sending path info to a log file path.log:
in controller Profilers, function confirmMember:
public function confirmMember()
{
//use_ssl();
$this->form_validation->set_rules('handle', 'Unique Member Name', 'trim|xss_clean|required|min_length[5]|max_length[30]');
$this->form_validation->set_rules('confirmation', 'Confirmation Code', 'trim|xss_clean|required|min_length[20]|max_length[20]|alpha_numeric');
if ($this->form_validation->run() === FALSE) {echo "here";exit;
$data['handle']=$this->input->post('handle');
$data['confirmation']=$this->input->post('confirmation');
$this->load->view('signing/defaults/header',$data);
$this->load->view('defaults/heading',$data);
$this->load->view('defaults/banner');
$this->load->view('defaults/banner_right');
$this->load->view('member/temp/index',$data);
$this->load->view('defaults/footer',$data);
} else {
$post = $this->input->post(NULL,TRUE);
$data['member'] = $this->Signing_model->model_confirmMember($post);
if ($data['member']['confirmed']!==FALSE) {
/* PATH CHECK */
error_log("member confirmation not false\n",3, LOG_DIR.'path.log');
unset($post);
$this->session->sess_destroy();
$this->session->set_flashdata('topic', 'newmember');
// $this->session->keep_flashdata('topic');
redirect('login','refresh');
} else {
/* PATH CHECK */
error_log("member confirmation IS FALSE\n",3, LOG_DIR.'path.log');
$this->load->view('member/temp/index',$data);
}
My log file shows that the path is using the correct path and showing "member confirmation not false".
I have tried with keep_flash data on (which I assumed wouldn't work since there are no other redirects) and off.
I have also tried redirect without 'refresh'.
In config/routes.php:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
$route['join'] = 'profilers/joinUp';
$route['login'] = 'profilers/signIn';
...
Login page uses Profilers Controller, signIn function as show above:
public function signIn()
{
$topic = $this->session->flashdata('topic');
if (isset($topic)) {
$message = "topic is set. topic = ".$topic."\n";
if ($topic!==FALSE) {
error_log("flash var topic is not false\n", 3, LOG_DIR.'path.log');
} else {
error_log("flash var topic is FALSE\n", 3, LOG_DIR.'path.log');
}
} else {
$message = "topic is NOT set\n";
}
error_log($message,3,LOG_DIR.'path.log');
exit;
...
...
}
log file is showing that topic is set but is false.
"flash var topic is FALSE"
"topic is set. topic = "
Of course topic var not set since it is FALSE.
As you can see, I have moved the get flash data function to the beginning of my controller function to bypass anything that may be corrupting data.
You may need to start the session again after you have destroyed it.
Try adding this after your call to sess_destory():
$this->session->sess_create()
Alternatively you could avoid destroying the session, and unset() the values you wish to get rid of.

change any rule in codeigniter to match function

I have set up my routes.php to suit the nature of my site. Unfortunately, there is a problem with my last route i.e.:
$route['(:any)'] = "profile/profile_guest/$1";
If the username password name passed is correct, for e.g. domain.com/username, it will load his/her data. if not, it loads the page with errors (because failure to retrieve data with non-existent user in database). This is my problem! I want to avoid this error showing.
Is there anyway I could avoid this error from happening? None of the echoes seems to be printing or the redirect neither is working. Don't know why! it is as if the code inside this method is not executing and the view is loaded instead. below is part of the profile_guest function:
public function profile_guest($username)
{
$username = $this->uri->segment(1);
//echo "Hello " . $username;
redirect('main', 'refresh');
if($username != '')
{
/* echo "<h1>HELLO WORLD SOMETHING</h1>"; */
It's hard to say without seeing the rest of the code.
Maybe you need to check the value before running the query:
// user_model
function get_user($username = NULL){
if($username){
return $this->db->query(...
}else{
return false;
}
}
Then check that the query returned anything before loading the view
if($this->user_model->get_user($username){
//show the page
}else{
echo "no user found";
}

Codeigniter catch database errors

I'm looking for a way to catch all the database errors (if and when they occur) and sent an error report my email. For regular php error I extended the CI_Exceptions class and added my email sending code in addition to logging. But the database errors don't go trough CI_Exceptions but instead are logged directly from CI_DB_Driver->query() and I don't want to modify any file in the System folder.
Also I don't want to write logging code around every query the app does.
I'd be tempted to extend CI_Exceptions show_error method to catch any errors passed with the 'error_db' template rather than hunting through the db driver.
As you've already extended CI_Exceptions with email code this would seem like the best practice.
function show_error($heading, $message, $template = 'error_general', $status_code = 500)
{
set_status_header($status_code);
$message = '<p>'.implode('</p><p>', ( ! is_array($message)) ? array($message) : $message).'</p>';
if ($template == 'error_db')
{
// do email send here with $message
}
if (ob_get_level() > $this->ob_level + 1)
{
ob_end_flush();
}
ob_start();
include(APPPATH.'errors/'.$template.'.php');
$buffer = ob_get_contents();
ob_end_clean();
return $buffer;
}

Magento losing messages after redirect

I have problem with magento messages. I am building custom module which in theory should be able to restrict access to some parts of the store. I have created an observer which hook into controller_action_predispatch event and checks if current request can be accessed by the user. If the action cannot be accessed the observer redirects user and sets the error info. I want to set the redirect url to the page the customer is coming from in order to avoid clicking through entire shop. I am looking at the HTTP_REFERER and use it if it is set, otherwise I redirect customer to homepage. The problem is that in the later case (homepage redirect) everything works great but when I set url based on the referer I do not see error message in message box.
The code from the observer ($name variable is a string):
Mage::getSingleton('core/session')->addError('Acces to '.$name.' section is denied');
$url = Mage::helper('core/http')->getHttpReferer() ? Mage::helper('core/http')->getHttpReferer() : Mage::getUrl();
Mage::app()->getResponse()->setRedirect($url);
What I found interesting is that if I do any change in the observer file and save it, then the next request which fails and gets redirected to referer url shows the error information but any subsequent loses the messages.
I was thinking that the problem is in the full url and my local instalation (I am using .local domain) but so I tried adding
$url = str_replace(Mage::getBaseUrl(), '/', $url);
but this did not helped.
I also tried redirect using php header() function without any result as well.
All cache is disabled. The workflow which triggers the problem is as follows:
I'm going to any accessible page (for example /customer/account)
Click on cart link (cart for this account is disabled)
Return to /customer/account and the error message is displayed
Click on cart link again
Return to /customer/account but no error message
Any hint on where to look will be appreciated.
//A Success Message
Mage::getSingleton('core/session')->addSuccess("Some success message");
//A Error Message
Mage::getSingleton('core/session')->addError("Some error message");
//A Info Message (See link below)
Mage::getSingleton('core/session')->addNotice("This is just a FYI message...");
//These lines are required to get it to work
session_write_close(); //THIS LINE IS VERY IMPORTANT!
$this->_redirect('module/controller/action');
// or
$url = 'path/to/your/page';
$this->_redirectUrl($url);
This will work in a controller, but if you're trying to redirect after output has already been sent, then you can only do that through javascript:
<script language=”javascript” type=”text/javascript”>
window.location.href=”module/controller/action/getparam1/value1/etc";
</script>
Your messages get lost because you use an unfavorably way for a redirect in controller_action_predispatch. Your solution causes on the one hand the "message lost" and on the other hand, it wastes processing power of your server.
When you take a look at Mage_Core_Controller_Varien_Action::dispatch(), you'll see that your solution doesn't stop the execution of the current action, but it should do that with a redirect. Instead Magento executes the current action to its end, including the rendering of the message you had added before. So no wonder why the message gets lost with the next client request, Magento had it already rendered before, with the server response which includes your redirect.
Further you'll see in Mage_Core_Controller_Varien_Action::dispatch() only one possibility to stop the execution of the current action and skip directly to the redirect, which is in line 428 catch (Mage_Core_Controller_Varien_Exception $e) [...]. So you have to use Mage_Core_Controller_Varien_Exception which is quite unpopular, but the only right solution for your purpose. The only problem is, this class has a bug since it was introduced in Magento 1.3.2. But this can be easily fixed.
Just create your own class which is derived from Mage_Core_Controller_Varien_Exception:
/**
* Controller exception that can fork different actions,
* cause forward or redirect
*/
class Your_Module_Controller_Varien_Exception
extends Mage_Core_Controller_Varien_Exception
{
/**
* Bugfix
*
* #see Mage_Core_Controller_Varien_Exception::prepareRedirect()
*/
public function prepareRedirect($path, $arguments = array())
{
$this->_resultCallback = self::RESULT_REDIRECT;
$this->_resultCallbackParams = array($path, $arguments);
return $this;
}
}
So you can now implement your solution realy clean with that:
/**
* Your observer
*/
class Your_Module_Model_Observer
{
/**
* Called before frontend action dispatch
* (controller_action_predispatch)
*
* #param Varien_Event_Observer $observer
*/
public function onFrontendActionDispatch($observer)
{
// [...]
/* #var $action Mage_Core_Model_Session */
$session = Mage::getSingleton('core/session');
/* #var $helper Mage_Core_Helper_Http */
$helper = Mage::helper('core/http');
// puts your message in the session
$session->addError('Your message');
// prepares the redirect url
$params = array();
$params['_direct'] = $helper->getHttpReferer()
? $helper->getHttpReferer() : Mage::getHomeUrl();
// force the redirect
$exception = new Your_Module_Controller_Varien_Exception();
$exception->prepareRedirect('', $params);
throw $exception;
}
}
this will work , so try it:
$url = 'path/to/your/page';
$this->_redirectUrl($url);
return false;
This means you are not allowing again to execute anything else.

How to log Magento "404" pages

I'm running a Magento Community website (on version 1.5.1) and I'm having an issue with "404" pages.
We have users landing on our site from direct links and also google/bing search results. The pages they go to may not be correct as they may have changed. Magento uses MVC to route requests to the correct controller, but when there isn't a controller Magento displays a static CMS page (i.e. "404" page). The problem is that this page doesn't allow me to write custom PHP code on it so I can't log the URL that caused the 404.
If I can find the right point in the code prior to displaying the CMS 404 page then I can log the URL and use that to do the appropriate URL rewriting.
Can someone help me as to where the code is that finally gives up on any controller and displays the custom CMS "404" page?
Basically this is happening in Mage_Cms_IndexController::noRouteAction(). But you also could just have a look at your webservers log for entries with the 404 return code (404 is set in the same method).
Alex was spot-on with his answer. I thought I'd post the code I wrote to solve the problem based on his answer.
/**
* Render CMS 404 Not found page
*
* #param string $coreRoute
*/
public function noRouteAction($coreRoute = null)
{
$this->getResponse()->setHeader('HTTP/1.1','404 Not Found');
$this->getResponse()->setHeader('Status','404 File not found');
/* JCS */
$path = $this->getRequest()->getPathInfo();
if (!startsWith($path, '/media/')) {
if (!startsWith($path, '/images/')) {
if (!startsWith($path, '/ebay/')) {
if (!startsWith($path, '/app/')) {
Mage::log('JCS:noRouteAction:path:'.$path);
}
}
}
}
$pageId = Mage::getStoreConfig(Mage_Cms_Helper_Page::XML_PATH_NO_ROUTE_PAGE);
if (!Mage::helper('cms/page')->renderPage($this, $pageId)) {
$this->_forward('defaultNoRoute');
}
}
I also added a startsWith function:
/* JCS */
function startsWith($haystack, $needle)
{
$length = strlen($needle);
return (substr($haystack, 0, $length) === $needle);
}

Resources