Hi,
is it possible to share informations between a PHP-Script and .htaccess?
I was experimenting with $_ENV, but did not get it to work.
What I want to do:
Creating a login system. For every html-request, .htaccess is calling (via reWrite rule) a php and passing as parameter the original url.The PHP is testing if the user is logged in. If not: Go to the login page, if yes: Allow accessing the requested URL. That I did with php "header($url)".
The problem: This always starts a loop, because the PHP script is, after the logged-test is successfull, requesting the original url, which as again handled in the .htaccess by calling the PHP-Script.
My idea: Is there a way to set a variable in PHP, which I can access in .htaccess-condition? And is that a secure way?
Update:
As asked for, here my code.
PHP:
session_start();
$sOriginUrl = $_GET["url"];
if(!$sOriginUrl){
return false;
}
if($_SESSION["userName"]) {
if($_SESSION["userName"] !== null){
header("Location: " . $sOriginUrl, TRUE, 301);
}
else {
$aTokenizedOriginalUrl = explode("/", $sOriginUrl);
$sLoginUrl = "/";
for($i=0, $il=count($aTokenizedOriginalUrl); $i<($il-1); $i++) {
$sLoginUrl = $sLoginUrl . $aTokenizedOriginalUrl[$i] . "/";
}
header("Location: //myurl.de/" . $sLoginUrl);
}
}
else {
$aTokenizedOriginalUrl = explode("/", $sOriginUrl);
$sLoginUrl = "/";
for($i=0, $il=count($aTokenizedOriginalUrl); $i<($il-1); $i++) {
$sLoginUrl = $sLoginUrl . $aTokenizedOriginalUrl[$i] . "/";
}
$_ENV["HTTP_user_logged"]="true";
header("Location: //myurl.de/" . $sLoginUrl);
}
.htaccess:
RewriteEngine on
# This prevents the rewrite engine from looping
RewriteCond %{ENV:HTTP_user_logged} true
#RewriteCond %{forced_responsecode} 301
RewriteRule ^ - [L]
#RewriteCond %{ENV:REDIRECT_STATUS} !=""
RewriteCond %{HTTP_REFERER} !^/myurl.de/basics/validate-user-login-for-url.php$
RewriteCond %{REQUEST_URI} !^(/.*)/$
RewriteCond %{REQUEST_URI} !^(/.*)/index.html$
RewriteRule ^(.*\.html)$ /myurl.de/basics/validate-user-login-for-url.php?url=%{REQUEST_URI}&ref=%{HTTP_REFERER} [L,QSA]
Thanks for any help!!
I'm afraid what you are asking is not possible. PHP cannot share information with .htaccess because the latter is checked before PHP is executed, so the workflow is "req ->.htaccess -> php; req -> .htaccess -> php", but the only thing is preserved between requests is cookies, and no it's not secure to save the login state in the cookie, you need to use sessions, and PHP sessions are not available in .htaccess
So the solution I propose is that every file in your project which requires user to be authenticated includes a file "check_auth.php" at the beginning, then your check_auth.php can include() the login page and exit() if not logged in, or simply do nothing if the user is logged in (which means the originally invoked script continues its execution.
Hope this helps. Cheers
Related
After changing from HTTP to HTTPS in my OpenCart installation with Journal2 theme/plugin I have problem - admin panel for Journal2 not loads, showing "Loading..." state and that's all.
Journal2 version = 2.13
OpenCart version = 2.3.0.2
Current stack: PHP 7 + Apache2 + MySQL
Also adding screenshot.
What is broken? I have updated website url from http:// to https:// in admin panel, also updated variables in
config.php
and
/admin/config.php
files. Maybe problems with caching?
Kindly check the two config files for correct configuration of Data Base and file folders.
Also u need to check the file in system/library/url.php
on that,
public function link($route, $args = '', $secure = false) {
if ($this->ssl && $secure) {
$url = 'https://' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['SCRIPT_NAME']), '/.\\') . '/index.php?route=' . $route;
} else {
$url = 'http://' . $_SERVER['HTTP_HOST'] . rtrim(dirname($_SERVER['SCRIPT_NAME']), '/.\\') . '/index.php?route=' . $route;
}
if ($args) {
if (is_array($args)) {
$url .= '&' . http_build_query($args);
} else {
$url .= str_replace('&', '&', '&' . ltrim($args, '&'));
}
}
foreach ($this->rewrite as $rewrite) {
$url = $rewrite->rewrite($url);
}
return $url;
}
Hope It will helps you.
Did you properly configure your site for SSL use? Let's go over some things here:
Not to sound repetitive, but are you very sure that both your config files are correct? Not sure what you meant before when you said you took "the path for the root" from some page when it's pretty much the url that anyone's going to go visit your site/store. I'm assuming your store/opencart is in it's own folder and not in the root directory, yes? If so:
admin/config.php file should have something like this:
// HTTP
define('HTTP_SERVER', 'http://www.yourwebsite.com/opencart/admin/');
define('HTTP_CATALOG', 'http://www.yourwebsite.com/opencart/');
// HTTPS
define('HTTPS_SERVER', 'https://www.yourwebsite.com/opencart/admin/');
define('HTTPS_CATALOG', 'https://www.yourwebsite.com/opencart/');
config.php file should have something like this:
// HTTP
define('HTTP_SERVER', 'http://www.yourwebsite.com/opencart/');
// HTTPS
define('HTTPS_SERVER', 'https://www.yourwebsite.com/opencart/');
and by what I recall from past experience that forward slash matters at the end.
Also, it matters very much if your url is: yourwebsite.com vs www.yourwebsite.com just to point out that, too.
Speaking of which... how about your .htaccess file? That could be a culprit here, too. I'm referring to the htaccess file for your root directory and not opencart's htaccess. That may need to be altered correctly to for https. As an example:
Options +FollowSymlinks
RewriteEngine on
RewriteCond %{SERVER_PORT} 80
RewriteRule ^(.*)$ https://www.yourwebsite.com/$1 [R,L]
RewriteCond %{HTTP_HOST} ^(www.)?yourwebsite.com$
RewriteCond %{REQUEST_URI} !^/opencart/
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ /opencart/$1
RewriteCond %{HTTP_HOST} ^(www.)?yourwebsite.com$
RewriteRule ^(/)?$ opencart/index.php [L]
If you notice here, you need to include the server port and https. So maybe check that, too.
Our site allows for a pretty url 'etest.me/1234' where '1234' is a client id. As you can see below it redirects to our route.php file where we do our redirect. The problem is when a client uses 'etest.me' without the '/1234' they get the apache 'The requested URL /go/ was not found on this server.' message. I would like the url to go to another page when the '/1234' is missing.
Note that we have the domain and path forwarded to the non-existing '/go' directory so the rules below will catch it. The following is in our .htaccess file in the root directory.
RewriteEngine On
#restrict rewriting URLs ONLY to paths that DO NOT exist
RewriteCond %{SCRIPT_FILENAME} !-d
# commented out to speed up looking since we are not processig file names anyway
#RewriteCond %{SCRIPT_FILENAME} !-f
RewriteRule ^go/([a-zA-Z0-9/]+)$ ./route\.php?go=$1
Working perfectly fine for me. Hope this will work for you as well.
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^go/([a-zA-Z0-9]+)$ /route.php?go=$1 //when client id exist
RewriteRule ^([a-zA-Z0-9]+)$ /index.php // when no client id
You can add a new rule to handle this situation:
RewriteRule ^go/$ ./another_script\.php
I accepted the answer by Sahil and posted the entire logic below for others to use:
Domain: etest.me
Pretty URL: etest.me/1234 (where '1234' is a client id)
Forwarded to: etesting.io/go (with forward path option selected so the '/1234' will be include in the forward)
Note: There is no '/go' directory on the server, '/go' is used to trigger the redirect.
Wanted 'etest.me' (without client id) to go to index file in root directory.
Here is the rewrite rules in .htaccess:
RewriteEngine On
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^go/([a-zA-Z0-9/]*)$ ./route\.php?go=$1
Here is the route.php code:
<?php
if($_GET['go']){
$a = explode('/', $_GET['go']);
$c = count($a);
if($c == 1 || $c == 2){
header('location: ../../index.php?aid=' . $a[0] . '&tid=' . $a[1]);
exit;
}
else{
die('Invalid URL');
}
}
else{
header('location: ../index.php');
exit;
}
And finally the index.php file:
if($_GET['aid'] && $_GET['tid']){
header('location: test/register.php?aid=' . $_GET['aid'] . '&tid=' . $_GET['tid']);
exit;
}
elseif($_GET['aid']){
header('location: test/index.php?aid=' . $_GET['aid']);
exit;
}
else{
header('location: account/index.php?' . $_SERVER['QUERY_STRING']);
exit;
}
Hope this helps somebody in the future.
I would like a more elegant solution but it's behind me for now...
I have this huge issue that I have no idea how to fix. I have a script that redirects to a url.
So far I have:
//do some mysql
$geo_included = true; //trying to fix infinite redirect loop.
if($geo_included === true){
header('Location: '.$url["url"]); //this is causing the issue with redirect loop
}
$url["url"] for example is: www.google.com
But when I go to that PHP file it will redirect to:
www.sitename.com/www.google.com
and say there is an infinite redirect loop. Note: the above header location script is not in a while/for/foreach loop.
Here is my .htaccess for the / directory
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php?group=$1 [L]
Any ideas?
You need to include the fully qualified domain name with scheme, otherwise it's interpreted as being in the current domain:
header('Location: google.com'); // Redirects to http://cursite.com/www.google.com
header('Location: http://google.com'); // Redirects as expected
If you are unsure if your URL includes a scheme, check the results from parse_url.
$url_scheme = parse_url($url, PHP_URL_SCHEME);
// www.google.com -> NULL
// http://google.com -> string(4) "http"
// ftp://site.com -> string(3) "ftp"
The quick proof-of-concept solution here is to prepend http:// to the URL like this:
$geo_included = true;
if ($geo_included) {
header('Location: http://' . $url["url"]);
}
I say “proof of concept” because what you should do is ensure the $url["url"] always has a protocol attached to it. Either before it gets into the database, or in this code snippet by doing a check on the $url["url"] value to see of it has http:// or https:// and if it doesn’t, prepend it. And here is a quickly thrown together example of what I mean which should work:
$geo_included = true;
if ($geo_included) {
$protocol = (!preg_match("~^(?:ht)tps?://~i", $url["url"])) ? 'http://' : null;
header('Location: ' $protocol . $url["url"]);
}
The line with $protocol = … does the check I explained before. The default is to add http:// if it’s not there.
Also, note I removed === true since the if ($geo_included) { is basically the same thing.
I have decided to build a web application using clean urls. However its seems to be quite hard for at first. I have experienced many problems during testing and I couldn't figure out how is it recommended to build Clean URLs basically.
I have finally decided to redirect everything to the index.php and process the URI from there.
This is my .htaccess file:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule .* index.php?url=$0 [QSA]
In the PHP end I have created this, so only the URLs in the array will be passed:
$root_path = '/';
$uri = $_SERVER['REQUEST_URI'];
$url = array(
$root_path . 'login' => 'login'
);
$url_basic = array_keys($url);
$url_slash = array_keys($url);
array_walk($url_slash, function(&$value, $key) { $value .= '/'; return $value;});
if (in_array($uri, $url_basic) || in_array($uri, $url_slash)) {
$uri = rtrim($uri,'/');
require $url[$uri] . '.php';
exit();
} else {
echo 'Bad';
}
So basically if someone types: /login or /login/ they'll have the login.php required, otherwise they'll stay on the index.php page (as APACHE redirects everything else).
Question:
Let's say that the user has received an error while trying to log in. In this case I guess the best way (or if its not the best way, please tell me) to pass a $_GET variable with the name of 'error' for example. So the user would get: /login/?error=1
How is it possible to achieve that result? Because if I type that I get redirected to the index.php page. Can anyone please help me?
You can look at $_SERVER['QUERY_STRING'] at cut the query string out of $_SERVER['REQUEST_URI']:
if ($_SERVER['QUERY_STRING'])
echo substr($_SERVER['REQUEST_URI'], 0, -strlen($_SERVER['QUERY_STRING']) - 1);
The -1 is there to remove the question mark as well.
But setting the error in GET is not necessary. You can use a flash message and store the error in the session. You can find a simple way to use them here.
Maybe you should consider using a routing system as that of
Symfony: http://symfony.com/doc/current/book/routing.html
or its slimmer counterpart
Silex: http://silex.sensiolabs.org/doc/usage.html#routing
how can i auto redirect a site from dirty url to clean url in php , something like
http://www.mysite.com?page=page1&action=action1
to
http://www.mysite.com/page1/action1
You have to check if it was clean request or not.
Otherwise you will fall into infinite loop
Here is an example from one of my projects:
.htaccess
RewriteEngine On
RewriteRule ^game/([0-9]+)/ /game.php?newid=$1
game.php
if (isset($_GET['id'])) {
$row = dbgetrow("SELECT * FROM games WHERE id = %s",$_GET['id']);
if ($row) {
Header( "HTTP/1.1 301 Moved Permanently" );
Header( "Location: /game/".$row['id']."/".seo_title($row['name']));
} else {
Header( "HTTP/1.1 404 Not found" );
}
exit;
}
if (isset($_GET['newid'])) $_GET['id'] = $_GET['newid'];
So, you have to verify, if it was direct "dirty" call or rewritten one.
And then redirect only if former one.
You need some code to build clean url too.
And it is also very important to show 404 instead of redirect in case url is wrong.
If you are running Apache you can use the mod_rewrite module and set the rules in a .htaccess file in your httpdocs folders or web root. I don't see any reason to invoke a PHP process to do redirection when lower level components will do the job far better.
An example from Simon Carletti:
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/page\.php$
RewriteCond %{QUERY_STRING} ^id=([0-9]*)$
RewriteRule ^(.*)$ http://mydomain.site/page/%1.pdf [R=302,L]
try
header("Location: http://www.mysite.com/".$_GET['page']."/".$_GET['action']);
you should check whether the values are set before trying to redirect