24

I have a php file say "check.php" in my website and it is executed when a form is submitted.

say my website is "myweb.com" and the php file is in a directory "PHP"

I want to prevent direct url access to the "check.php" file i.e. if anyone types the url "myweb.com/PHP/check.php" ,then the php file should not be executed and it should return a error message instead.

I tried to prevent the access by setting a rule in .htaccess ,but it blocks the php even when I try to submit the form.

.htaccess rule :

RewriteEngine on 
RewriteCond %{THE_REQUEST} \.php[\ /?].*HTTP/ 
(.*)\.php$ /index.html [L] 

Is there any possible way to do it ?

Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
It Assistors
  • 998
  • 2
  • 14
  • 29

9 Answers9

37

You can do it with PHP

<?php
    /* at the top of 'check.php' */
    if ( $_SERVER['REQUEST_METHOD']=='GET' && realpath(__FILE__) == realpath( $_SERVER['SCRIPT_FILENAME'] ) ) {
        /* 
           Up to you which header to send, some prefer 404 even if 
           the files does exist for security
        */
        header( 'HTTP/1.0 403 Forbidden', TRUE, 403 );
        die;
    }
Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
Professor Abronsius
  • 33,063
  • 5
  • 32
  • 46
  • I added it to my php file, but it is redirecting it to the error page even at the form post action. Is there anyway to exclude the post method – It Assistors Nov 30 '15 at 13:35
  • 1
    sorry about that - hopefully that would do the trick. However, @Starkeen's method of using the `.htaccess` file is probably better ~ though using PHP does allow you to do other things before redirecting the user - ie: log the hit to the db etc – Professor Abronsius Nov 30 '15 at 13:38
  • 2
    your method worked like charm. I just applied a little edit instead of $_SERVER['REQ.....] == 'GET' I used .... != 'POST' as I use post method and it should display the error only if the request is not 'post' Thank You... – It Assistors Nov 30 '15 at 13:43
  • Was hopeful but couldn't get this to work. Maybe I'm not understanding, but I wrote a short PHP to just exit() with response string showing the contents of realpath( $_SERVER['SCRIPT_FILENAME']) and realpath(__FILE__). Whether I plugged a path to the script right into a browser, or ran it from an XMLHttpRequest() on a page, both strings were identical. I'm blocking direct attempts with cookies and it seems to work. Just a nuisance when i see my logs filled with some idiot trying and trying. Wish there were a way, like a BROWSER array or something. – Randy Jun 24 '19 at 22:07
19

Put this code at the top of check.php:

if(!isset($_SERVER['HTTP_REFERER'])){
    // redirect them to your desired location
    header('location:../index.php');
    exit;
}

If the user access check.php by type the URL directly, it will redirect them to your desired location.

Westly Tanbri
  • 327
  • 1
  • 3
  • 8
  • 6
    I wouldn't recommend this. Some browsers (like Firefox) allow users to suppress the Referer header for privacy reasons. – Richard Szalay Oct 24 '17 at 05:24
  • Old post here, but thanks! I'll add it in. I've herd time and again that the HTTP_REFERER variable can be spoofed, but its still another harmless tool to fend off some folks trying to bang on my script, filling my logs with hack attempts. And if you already have pretty modals to warn your visitors to make sure cookies are enabled, etc, when scripts fail, I guess to a certain extent the failure to be able to use a page resource I provide is their own fault.. – Randy Jun 24 '19 at 22:20
3

Try this in Root/.htaccess :

RewriteEngine on


RewriteCond %{REQUEST_METHOD} !^POST$
RewriteRule ^php/check.php$ - [NC,R=404,L]

This will return 404 not found if check.php is not accessed by form post method.

Amit Verma
  • 40,709
  • 21
  • 93
  • 115
3

I tried the selected answer but i ran into some issues implementing it, specially if i wanted to return values from functions inside the PHP file using GET with Ajax.

After doing quite an extensive research on other solutions (and a little testing of my own), i came up with the following code:

<?php
$currentPage = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";

if ($_SERVER['REQUEST_METHOD'] == "GET" && strcmp(basename($currentPage), basename(__FILE__)) == 0)
{
    http_response_code(404);
    include('myCustom404.php'); // provide your own 404 error page
    die(); /* remove this if you want to execute the rest of
              the code inside the file before redirecting. */
}
?>

I found that the code above worked as i wanted and i don't think it would have any problems with multiple browser like the other answer was pointed out to have. I also don't think it would have any security issues, but i could be wrong (please tell me if i am (and why)), i'm relatively new to web programming.

Just add that code on top of every file you would want to block direct URL access (before everything, even requires, includes and session_starts) and you are good to go.

Martin Koch
  • 185
  • 1
  • 2
  • 7
  • A query string (?) at the end of the URL breaks this probably because the current page does not match the filename. – singhnsk Mar 13 '21 at 22:00
1

this is what google uses in their php examples

if (php_sapi_name() != 'cli') {
  throw new \Exception('This application must be run on the command line.');
}
Toskan
  • 13,911
  • 14
  • 95
  • 185
0
if (basename($_SERVER['SCRIPT_FILENAME']) === 'common.php')
{
    exit('This page may not be called directly!');
}
Erik Thiart
  • 381
  • 6
  • 17
0

Lot of answers to this question but I did something like this.

<?php
    $page = basename($_SERVER['PHP_SELF']);
    
    if($page == "somefile.php"){
      header('Location: index.php');
    }
 ?>
Mohammed Khurram
  • 616
  • 1
  • 7
  • 14
-1

Try this one too. Past in the top of check.php

<?php debug_backtrace() || die ("<h2>Access Denied!</h2> This file is protected and not available to public."); ?>

An Access Denied will be presented when the file is access directly in the url

icynets
  • 337
  • 2
  • 5
-1

In my case there was a problem with Ajax.

It works for me.

if(!isset($_SERVER['HTTP_X_REQUESTED_WITH']) && ($_SERVER['HTTP_X_REQUESTED_WITH'] !== 'XMLHttpRequest')) {
  exit("Direct access denied.");
}