Save HTTP_REFERER with mod_rewrite? - .htaccess

actually I'm trying to pass referers inside the .htaccess. What I'm trying to do is that the referer value shall be send to a PHP script where this value will be saved to a databse. In some cases (depending on the referer) the image shall be blocked (hot linking) and in some other cases the image shall be shown normally. But it will not work :-( My current "try" looks like the following (it is just for testing, so currently every image will be handled):
RewriteCond %{REQUEST_URI} (.*)jpg$
RewriteCond %{ENV:verified} ^$
RewriteRule (.*)jpg$ /include/referrer.php?ref=%{REQUEST_FILENAME}&uri=%{REQUEST_URI}&query=%{QUERY_STRING}&env=%{ENV:verified} [E=verified:yes]
RewriteCond %{REQUEST_URI} (.*)jpg$
RewriteCond %{ENV:verified} ^yes$
RewriteRule ^(.*)$ %{REQUEST_FILENAME} [E=verified:no]
The referrer.php look like:
<?
log_img($_REQUEST['uri'].' - "'.$_REQUEST['env'].'"');
?>
The problem is that the referrer.php is called but the image will not be displayed, which is obvious because the second rule is not reached.
I also have tried to display the image inside of the referrer.php, like:
<?
log_img($_REQUEST['uri'].' - "'.$_REQUEST['env'].'"');
$src = str_replace($_SERVER['DOCUMENT_ROOT'],'',$_REQUEST['ref']);
?>
<img src="<? echo $src ?>" />
But then the .htaccess is called again and I will run into endless loops.
The question is now: how can I access the second rule or how can I achieve what I want to do. Is there any way to do that?
Thanks for your help,
Lars

Your current solution doesn't work because mod_rewrite can only be used to rewrite the request to a single destination, but you seem to want the request to take a detour to your PHP script, then continue onward to the image. It might be possible to cause a subrequest that would cause the PHP script to get triggered, but I don't think it would be possible to control whether or not the original request continued on to the image in that scenario.
The best course of action here is to have your PHP file print out the actual image data (not an image tag referencing the image) after it does whatever checking/logging you intend it to do. You can do this with readfile(), provided that you send the right headers. After making sure the file is one of the images you want to serve up (and not some arbitrary file on your system...), you'll at least need to determine the appropriate content type, then print out the data. It's also a good idea to take caching (see this answer, as well as this one) into consideration.
Combining some of the techniques mentioned, a simple pseudo-example of the referrer script would be as follows. Note that you should research the best way to implement the techniques described, and you need to pay particular attention to security since you're opening files and printing their contents.
$filename = /* sanitized file name */;
log_img(/* log some data about the request */);
if (file_exists($filename) && allowedToView($filename)) {
// Assume we're not on PHP 5.3...
$types = array(
'gif' => 'image/gif',
'png' => 'image/png',
'jpg' => 'image/jpg',
);
$parts = pathinfo($filename);
$ext = strtolower($parts['extension']);
if (array_key_exists($ext, $types)) {
$mime = $types[$ext];
$size = filesize($filename);
$expires = 60 * 60 * 24 * 30;
if (!empty($_SERVER['IF-MODIFIED-SINCE'])) {
$modified = filemtime($filename);
$cached = strtotime($_SERVER['IF-MODIFIED-SINCE']);
if ($modified <= $cached) {
header('HTTP/1.1 304 Not Modified');
exit();
}
}
header("Content-Type: $mime");
header("Content-Length: $size");
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + $expires)
. ' GMT');
header('Cache-control: private, max-age=' . $expires);
readfile($filename);
exit();
}
}
header("HTTP/1.0 404 Not Found");
exit();
And as far as the .htaccess file goes, it would just be something like this (the stuff that you added to the query string is available in $_SERVER anyway, so I see no point in manually passing it to the script):
RewriteEngine on
RewriteRule \.(jpg|png|gif)$ /include/referrer.php [NC]

Related

how do i display the user nickname instead of the ID on the page profile [duplicate]

Normally, the practice or very old way of displaying some profile page is like this:
www.domain.com/profile.php?u=12345
where u=12345 is the user id.
In recent years, I found some website with very nice urls like:
www.domain.com/profile/12345
How do I do this in PHP?
Just as a wild guess, is it something to do with the .htaccess file? Can you give me more tips or some sample code on how to write the .htaccess file?
According to this article, you want a mod_rewrite (placed in an .htaccess file) rule that looks something like this:
RewriteEngine on
RewriteRule ^/news/([0-9]+)\.html /news.php?news_id=$1
And this maps requests from
/news.php?news_id=63
to
/news/63.html
Another possibility is doing it with forcetype, which forces anything down a particular path to use php to eval the content. So, in your .htaccess file, put the following:
<Files news>
ForceType application/x-httpd-php
</Files>
And then the index.php can take action based on the $_SERVER['PATH_INFO'] variable:
<?php
echo $_SERVER['PATH_INFO'];
// outputs '/63.html'
?>
I recently used the following in an application that is working well for my needs.
.htaccess
<IfModule mod_rewrite.c>
# enable rewrite engine
RewriteEngine On
# if requested url does not exist pass it as path info to index.php
RewriteRule ^$ index.php?/ [QSA,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?/$1 [QSA,L]
</IfModule>
index.php
foreach (explode ("/", $_SERVER['REQUEST_URI']) as $part)
{
// Figure out what you want to do with the URL parts.
}
I try to explain this problem step by step in following example.
0) Question
I try to ask you like this :
i want to open page like facebook profile www.facebook.com/kaila.piyush
it get id from url and parse it to profile.php file and return featch data from database and show user to his profile
normally when we develope any website its link look like
www.website.com/profile.php?id=username
example.com/weblog/index.php?y=2000&m=11&d=23&id=5678
now we update with new style not rewrite we use www.website.com/username or example.com/weblog/2000/11/23/5678 as permalink
http://example.com/profile/userid (get a profile by the ID)
http://example.com/profile/username (get a profile by the username)
http://example.com/myprofile (get the profile of the currently logged-in user)
1) .htaccess
Create a .htaccess file in the root folder or update the existing one :
Options +FollowSymLinks
# Turn on the RewriteEngine
RewriteEngine On
# Rules
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /index.php
What does that do ?
If the request is for a real directory or file (one that exists on the server), index.php isn't served, else every url is redirected to index.php.
2) index.php
Now, we want to know what action to trigger, so we need to read the URL :
In index.php :
// index.php
// This is necessary when index.php is not in the root folder, but in some subfolder...
// We compare $requestURL and $scriptName to remove the inappropriate values
$requestURI = explode(‘/’, $_SERVER[‘REQUEST_URI’]);
$scriptName = explode(‘/’,$_SERVER[‘SCRIPT_NAME’]);
for ($i= 0; $i < sizeof($scriptName); $i++)
{
if ($requestURI[$i] == $scriptName[$i])
{
unset($requestURI[$i]);
}
}
$command = array_values($requestURI);
With the url http://example.com/profile/19837, $command would contain :
$command = array(
[0] => 'profile',
[1] => 19837,
[2] => ,
)
Now, we have to dispatch the URLs. We add this in the index.php :
// index.php
require_once("profile.php"); // We need this file
switch($command[0])
{
case ‘profile’ :
// We run the profile function from the profile.php file.
profile($command([1]);
break;
case ‘myprofile’ :
// We run the myProfile function from the profile.php file.
myProfile();
break;
default:
// Wrong page ! You could also redirect to your custom 404 page.
echo "404 Error : wrong page.";
break;
}
2) profile.php
Now in the profile.php file, we should have something like this :
// profile.php
function profile($chars)
{
// We check if $chars is an Integer (ie. an ID) or a String (ie. a potential username)
if (is_int($chars)) {
$id = $chars;
// Do the SQL to get the $user from his ID
// ........
} else {
$username = mysqli_real_escape_string($char);
// Do the SQL to get the $user from his username
// ...........
}
// Render your view with the $user variable
// .........
}
function myProfile()
{
// Get the currently logged-in user ID from the session :
$id = ....
// Run the above function :
profile($id);
}
Simple way to do this. Try this code. Put code in your htaccess file:
Options +FollowSymLinks
RewriteEngine on
RewriteRule profile/(.*)/ profile.php?u=$1
RewriteRule profile/(.*) profile.php?u=$1
It will create this type pretty URL:
http://www.domain.com/profile/12345/
For more htaccess Pretty URL:http://www.webconfs.com/url-rewriting-tool.php
It's actually not PHP, it's apache using mod_rewrite. What happens is the person requests the link, www.example.com/profile/12345 and then apache chops it up using a rewrite rule making it look like this, www.example.com/profile.php?u=12345, to the server. You can find more here: Rewrite Guide
ModRewrite is not the only answer. You could also use Options +MultiViews in .htaccess and then check $_SERVER REQUEST_URI to find everything that is in URL.
There are lots of different ways to do this. One way is to use the RewriteRule techniques mentioned earlier to mask query string values.
One of the ways I really like is if you use the front controller pattern, you can also use urls like http://yoursite.com/index.php/path/to/your/page/here and parse the value of $_SERVER['REQUEST_URI'].
You can easily extract the /path/to/your/page/here bit with the following bit of code:
$route = substr($_SERVER['REQUEST_URI'], strlen($_SERVER['SCRIPT_NAME']));
From there, you can parse it however you please, but for pete's sake make sure you sanitise it ;)
It looks like you are talking about a RESTful webservice.
http://en.wikipedia.org/wiki/Representational_State_Transfer
The .htaccess file does rewrite all URIs to point to one controller, but that is more detailed then you want to get at this point. You may want to look at Recess
It's a RESTful framework all in PHP

How to setup mod_rewrite with fallbacks if target URL doesn't exist?

How can I setup mod_rewrite in such a way that if the target URL doesn't exist, it can check the next rule, and then the next, until it finds an existing URL?
My situation is that I have a set of image files on a remote CDN. I'm using mod_rewrite to obscure the actual URL of those images by rewriting like this (terribly simplified example):
THIS: http://mydomain.com/123456789/image.jpg?num=1
TO THIS: http://123456789.remoteserver.com/image1.jpg
THIS: http://mydomain.com/123456789/image.jpg?num=3
TO THIS: http://123456789.remoteserver.com/image3.jpg
Here's a simplified example of my current mod_rewrite to help visualize:
RewriteCond %{QUERY_STRING} ^num=([0-9]+)$
RewriteRule ^([0-9-]+)/image.jpg$ http://$1.remoteserver.com/image%1.jpg [P]
It works perfectly as is, but I need to complicate things a little so that if "image1.jpg" doesn't exist, it can check for "image2.jpg," and if that doesn't exist, it can check for "image3.jpg," etc. - up to 5 or 6 different images - and rewrite to the first existing URL it finds. Is this even possible?
It works perfectly as is, but I need to complicate things a little so that if "image1.jpg" doesn't exist, it can check for "image2.jpg," and if that doesn't exist, it can check for "image3.jpg," etc. - up to 5 or 6 different images - and rewrite to the first existing URL it finds. Is this even possible?
Not with mod_rewrite. When it gets to the [P] flag and ends its rewriting, the URL processing pipeline moves on, and mod_rewrite will never know how that request resolved. In other words, it'll never know if image1.jpg exists, if there was an error, if the request timed out, etc.
You'll have to probably employ a script or something to do this. For example, if you change your rules to:
RewriteCond %{QUERY_STRING} ^num=([0-9]+)$
RewriteRule ^([0-9-]+)/image.jpg$ /proxy_image.php?path=$1&num=%1 [L]
Then in the proxy_image.php script, have something like:
$num = $_GET['num'];
$success = false;
while($success == false) {
$image = "image" . $num . ".jpg";
$url = "http://" . $_GET['path'] . ".remoteserver.com/" . $image;
$contents = loadImageUrl($url);
if($contents === 0) {
$success = false;
$num++;
}
else {
returnToBrowser($contents);
break;
}
}
You'll have to write the pseudo functions in the code, but you get the idea.

Canonical Header Links for PDF and Image files in .htaccess

I'm attempting to setup Canonical links for a number of PDF and images files on my website.
Example Folder Structure:
/index.php
/docs/
file.pdf
/folder1/
file.pdf
/folder2/
file1.pdf
file2.pdf
/img/
sprite.png
/slideshow/
slide1.jpg
slide2.jpg
Example PDF URL to Canonical URL:
http://www.example.com/docs/folder1/file.pdf --> http://www.example.com/products/folder1/
I am trying to avoid having to put individual .htaccess files in each of the sub-folders that contain all of my images and PDFs. I currently have 7 "main" folders, and each of these folders have any where from 2-10 sub-folders, and most sub-folders have their own sub-folders. I have roughly 80 PDFs, and even more images.
I'm looking for a (semi)dynamic solution where all files in a certain folder will have the Canonical Link set to a single url. I want to keep as much as possible in a single .htaccess file.
I know that <Files> and <FilesMatch> do not understand paths, and that <Directory> and <DirectoryMatch> don't work in .htaccess files.
Is there a fairly simple way to accomplish this?
I don't know of a way to solve this with apache rules alone as it would require some sort of regex matching and reusing the result of the match in a directive, which isn't possible.
However, it's pretty simple if you introduce a php script into the mix:
RewriteEngine On
RewriteCond %{REQUEST_URI} \.(jpg|png|pdf)$
RewriteRule (.*) /canonical-header.php?path=$1
Note that this would send requests for all jpg, png and pdf files to the script regardless of the folder name. If you want to include only specific folders, you could add another RewriteCond to accomplish that.
Now the canonical-header.php script:
<?php
// Checking for the presence of the path variable in the query string allows us to easily 404 any requests that
// come directly to this script, just to be safe.
if (!empty($_GET['path'])) {
// Be sure to add any new file types you want to handle here so the correct content-type header will be sent.
$mimeTypes = array(
'pdf' => 'application/pdf',
'jpg' => 'image/jpeg',
'png' => 'image/png',
);
$path = filter_input(INPUT_GET, 'path', FILTER_SANITIZE_URL);
$file = realpath($path);
$extension = pathinfo($path, PATHINFO_EXTENSION);
$canonicalUrl = 'http://' . $_SERVER['HTTP_HOST'] . '/' . dirname($path);
$type = $mimeTypes[$extension];
// Verify that the file exists and is readable, or send 404
if (is_readable($file)) {
header('Content-Type: ' . $type);
header('Link <' . $canonicalUrl . '>; rel="canonical"');
readfile(realpath($path));
} else {
header('HTTP/1.0 404 Not Found');
echo "File not found";
}
} else {
header('HTTP/1.0 404 Not Found');
echo "File not found";
}
Please consider this code untested and check that it works as expected across browsers before releasing it to production.
I was able to achieve adding canonical links for files in different directories through a single .htacess file.
The following code adds a canonical link for each file pointing to the same directory:
<FilesMatch "\.(jpg|png|pdf)$">
RewriteRule ([^/]+)\.(jpg|png|pdf)$ - [E=FILENAME:%{HTTP_HOST}/<your-desired-location>/$1.$2]
Header add Link '<https://%{FILENAME}e>; rel="canonical"'
</FilesMatch>
And the code below adds a canonical link to the file's requested URL, which in many cases will be its actual location on the server:
<FilesMatch "\.(jpg|png|pdf)$">
RewriteRule ([^/]+)\.(jpg|png|pdf)$ - [E=FILENAME:%{HTTP_HOST}%{REQUEST_URI}]
Header set Link '<https://%{FILENAME}e>; rel="canonical"'
</FilesMatch>
Here is the solution !!!
you can use .htacess file for controlling header which is more simple way to manage headers.
How you can do ?
Lets take a example, I have a pdf named "testPDF.pdf" which is in the root folder of my site.
All you have to do, pasted following code into .htaccss file.
<Files testPDF.pdf >
Header add Link '<http://<your_site_name>.com/ >; rel="canonical"'
</Files>
Once you've added that to your .htaccess file, you'll need to test your header to ensure that it's working accurately
For an IIS solution, try something like this.
Response.AppendHeader("Link", "<" + "https://" + Request.Url.Host + "/" + product.GetSeName() + ">; rel=\"canonical\"");
this was added to a function which generated a PDF version of the webpage :)

Selecting for special characters with rewriterule in htaccess file

I made a little mistake (I started a new php call within an existing php call - oops) and managed to have google start crawling a whole bunch of urls that look like this:
http://www.mydomain.com/folder/parameter/%3C/?php%20echo%20writelink();%20?%3E
I've fixed the sourcing call, but my attempts to have .htaccess rewite the page calls to
http://www.mydomain.com/folder/parameter/
have been unsuccessful.
I have tried the following:
RewriteRule ^folder/(.*)/(.*)%(.*) /folder/$1/ [NE,R=301,L]
RewriteRule ^folder/(.*)/(.*)3C/?php /folder/$1/ [R=301,L]
RewriteRule ^folder/(.*)/(.*)writelink /folder/$1/ [R=301,L]
RewriteRule ^folder/(.*)/([^/.]+)writelink /folder/$1/ [R=301,L]
But all of them are returning the same 403.
I have the test rewriterule as the first rewriterule in the file, so it isnt being usurped by something else.
(For reference, the correct rewriterule when I havent mucked up the page is
RewriteRule ^folder/(.*)/$ /content/element.php?param=$1 [L]
)
I've had problems with %ages in the path before but this time I've decided to defeat it - any suggestions?
Your URL is something like this:
http://www.mydomain.com/folder/parameter/</?php echo writelink(); ?> whithout the encoding.
The 304 code does not really indicate an error, it indicates the resource for the requested URL has not changed since last accessed or cached. Clear your brower's cache and make sure it is cleared.
The error should be 403 (Forbidden) because of the initial character < (%3C).
These errors make any rewrite rule at .htaccess useless. One way to handle this kind of problem is with a script.
EXAMPLE
Add these lines to your .htaccess file at root directory:
Options +FollowSymlinks -MultiViews
ErrorDocument 403 /Error403.php
Create Error403.php at root directory with a content similar to this one:
<?php
// The following lines should be at the top of the file
/**************Only for Debugging**********************/
echo $_SERVER[ 'REDIRECT_QUERY_STRING' ] . "<br /><br />";
echo var_dump($_REQUEST) . "<br /><br />";
/*=====================================================
NOTE: A Header error might be generated while the above
code is active. Use it only to display the incoming
parameters and delete it for normal operation.
*******************************************************/
if ( isset ( $_SERVER[ 'REDIRECT_QUERY_STRING' ] ) ) {
$QueryString = $_SERVER[ 'REDIRECT_QUERY_STRING' ]; // The query looks like this: php%20echo%20writelink();%20?%3E
// Check if it is the wrong URL
if ( preg_match( '|php%20echo%20writelink()|i', $QueryString ) ) {
header("Location: http://www.mydomain.com/folder/parameter/");
}
}
// Handle other errors
?>
In this specific case we take advantage of the fact that the string contains a question mark ?, that makes it look like a query. So we try to match the query content with preg_match().
That should do it. Modify the links accordingly if necessary, this is just an example on how to do it.

htaccess - creating directories and files of the same name

I want to create a bunch of files without an extension showing at the end. The easiest way to do that was to do this:
/usa/index.php
/usa/alaska/index.php
/usa/alabama/index.php
/usa/california/index.php
What I want to do is this
/usa/alaska.php
/usa/alabama.php
/usa/california.php
and have it show up as:
/usa/alaska
/usa/alabama
/usa/california
However, I have one more level I want to add to this, the cities
/usa/alaska/adak.php
/usa/alaska/anchorage.php
/usa/california/los-angles.php
I don't want the ".php" showing up, but then each state exists as both a file and a directory. What I want is an htaccess rule that serves up the file version of the file, not the directory which is the default. I also want to strip the .php off of the end of the files so the final result looks like
/usa
/usa/alaska (alaska.php)
/usa/alaska/adak (adak.php)
I know I can get close to this by creating all the directories and using index.php for each directory, but then I will have thousands of directories each with one file in it and updating is a pain in the butt. I would much rather have one directory with 1000 files in it, than 1000 directories with 1 file in it.
Please, can someone point me in the right direction and know that I am doing this for all 50 states.
Jim
I would also suggest using a single php (e.g. index.php) file and redirecting all urls starting with usa to it, instead of separating them in different directories and files. The you'd need a couple of rewrite rules like the following
RewriteEngine On
RewriteRule ^usa/([^/.]+)$ index.php?state=$1 [L]
RewriteRule ^usa/([^/]+)/([^/.]+)$ index.php?state=$1&city=$2 [L]
So then in your index.php you'd only need to check the $_GET parameters.
Update:
If you don't feel comfortable enough to use a database and pull the needed data from there you could always use the parameters to dynamically include/require the needed files. Something like this
<?php
$source = ''; //or the 'ROOT' directory
if(isset($_GET['state'])) $source .= $_GET['state'].'/';
if(isset($_GET['city'])) $source .= $_GET['city'].'.php';
include($source); // here $source would be something like 'alaska/adak.php'
// and is assumed that the dir 'alaska' is on the same
// level as 'index.php'
?>
But to answer your original question nevertheless you could use the following .htaccess
RewriteEngine On
RewriteRule ^usa/([^/.]+)$ usa/$1.php [L]
RewriteRule ^usa/([^/]+)/([^/.]+)$ usa/$1/$2.php [L]
what about creating just one single file:
/usa/index.php
With
$_SERVER["REQUEST_URI"]
you can read the current URI.
Well, now if a user enters "http://domain.foo/usa/alaska" for example, he will get an 404 error of course.
But to call your index.php instead, you could write this line to the .htaccess:
ErrorDocument 404 /usa/index.php
Now the index.php receives everything what is written to the URI and you can match the result and include files or handle errors.
But maybe there is a better solution with .htaccess only, don't know. :)

Resources