I'm trying to create a basic REST style API with PHP and I'm having a strange issue. When I visit one of my pages (viewinput.php) through the URL /rest/viewinput.php the page loads fine. When I try through /rest/viewinput I get a "page not found" error.
So, here's the code that determines the type of request and where to send it. This is found on my server.php page
//in server.php
public function serve() {
$uri = $_SERVER['REQUEST_URI'];
$method = $_SERVER['REQUEST_METHOD'];
$paths = explode('/', $this->paths($uri));
array_shift($paths); //
$resource = array_shift($paths);
if ($resource == 'rest') {
$page = array_shift($paths);
if (empty($page)) {
$this->handle_base($method);
} else {
$this->handle_page($method, $page);
}
}
else {
// We only handle resources under 'clients'
header('HTTP/1.1 404 Not Found');
}
}
Since it is a GET method with a determined page name, it will be passed to this function
//in server.php
private function handle_page($method, $page) {
switch($method) {
case 'GET':
if($page == "viewinput"){ //I have both viewinput.php and viewinput just to check both. Only viewinput.php works
$this->display_info();
}
if($page == "viewinput.php"){
$this->display_info();
}
default:
header('HTTP/1.1 405 Method Not Allowed');
header('Allow: GET, PUT, DELETE');
break;
}
}
From here it is then sent to
//in server.php
function display_info(){
$view = new ViewInputs();
$view->view(); //this function is on viewinput.php
}
So, when I visit /rest/viewinput.php the view function displays properly. When I visit /rest/viewinput I get a "broken link" error.
I followed a tutorial online for a REST server Found Here and it works just fine.
The following is in my httpd.conf file
Options +FollowSymlinks
RewriteEngine on
RewriteRule ^/.* rest/server.php
This is my viewinput.php file. I believe that it's working correctly (when page loads, the serve function on server.php should run.
<?
include_once 'server.php';
class ViewInputs{
function view(){
$sql = mysql_query("select * from entry");
?>
<table>
<th>ID</th>
<th>Text</th>
<col width="200">
<col width="150">
<?
while ($result = mysql_fetch_array($sql)){
?>
<tr><td><? echo $result['id']." "; ?></td><td><? echo $result['text']; ?></td></tr>
<?
}
?> </table> <?
}
}
$server = new server();
$server->serve();
?>
From httpd.conf. I may be wrong, but I believe this is how to allow a .htaccess file
DocumentRoot "C:/xampp/htdocs/rest"
<Directory />
Options FollowSymLinks
AllowOverride ALL
Order deny, allow
Deny from none
</Directory>
<Files ".ht*">
Require all ALLOW
</Files>
Your rewrite rule is not written correctly. What is happening is that when you go to rest/viewinput.php that file actually exists so it is able to run. When you go to rest/viewinput that file doesn't exist. You can check your rewrite rule by going to http://martinmelin.se/rewrite-rule-tester/ you will see your rewrite rule is no good.
The point of doing this is so that you don't have a veiwinput.php file, everything should be sent directly to the server.php file. Most likely the rewrite rule you want is something like this:
RewriteRule rest/* rest/server.php
If you want to actually go to viewinput.php there is no point in having a rewrite rule at all, just get rid of it.
If you want rest/viewinput to be treated as rest/viewinput.php then use this:
RewriteRule ^rest/([a-z]+) rest/$1.php
Related
In order to include the right file and display an error page if an error occurs, I have the following code (very simplified) :
$page = 'examplePage.php';
$page404 = '404.php';
if (file_exists($page))
{
require($page);
}
else if (file_exists($page404))
{
require($page404);
}
else
{
// Tell the browser to display his default page
}
?>
To summarize :
If I have the file, I include it.
If I don't have the file, i include the error file.
What if the error file does not exist too ?
I would like it to be rendered as the default error page of the browser.
I already achieved this with Internet Explorer by sending an empty content with the HTTP error.
The problem is that the other browsers don't act the same, they all display a blank page.
Is there any way to tell browsers to display their own error page ? (not only 404, but all errors : 304, 500 etc)
Thank you.
Edit : I forgot to tell you that I have the complete control on the headers I send and on the content sent in response.
Edit 2 : here is some code
// possible paths to retrieve the file
$possiblePaths = array(
$urlPath,
D_ROOT.$urlPath,
D_PAGES.$urlPath.'.php',
D_PAGES.$urlPath.'/index.php',
$urlPath.'.php'
);
foreach ($possiblePaths as $possiblePath)
if (file_exists($possiblePath) && !is_dir($possiblePath))
{
if (!is_readable($possiblePath))
{
Response::setCode(403); // calls the header(403)
self::$filePath = self::getErrorPage(403);
}
else
self::$filePath = $possiblePath;
break;
}
if (self::$filePath === null) // no file found => 404
{
Response::setCode(404); // call the header(404)
self::$filePath = self::getErrorPage(404);
}
public static function _getErrorPage($code)
{
if (is_readable(D_ERRORS.$code.'.php')) // D_ERRORS is the error directory, it contains files like 404.php, 403.php etc
return D_ERRORS.$code.'.php';
else
{
/*-------------------------------------------------*/
/* Here i go if the error file is not found either */
/*-------------------------------------------------*/
if ($code >= 400)
Response::$dieResponse = true; // removes all output, only leaves the http header
return null;
}
}
?>
And here is when I print the content :
<?php
if (self::$dieResponse)
{
self::$headers = array(); // no more headers
self::$content = ''; // no more response
}
http_response_code(self::$code); // HTTP code
foreach (self::$headers as $key => $value)
header($key.': '.implode(';', $value)); // sends all headers
echo self::$content;
?>
Edit : here are some screenshots to explain what I want.
This is what i've got in IE :
This is exactly what i want.
Now, in all the other browsers, I've got a blank page. I don't want a blank page.
I want, for example, Chrome to display this :
Default error pages
Web Browsers shows default error pages if content is blank, eg. create a empty PHP file (error.php) and put this:
<?php
$status = http_response_code();
switch ($status) {
case 404:
case 500:
exit;//terminate script execution
break;
...
}
In .htaccess put:
ErrorDocument 400 /error.php
ErrorDocument 500 /error.php
Custom error pages
Using HTTP status
You can use http_response_code() for GET current HTTP status, .htaccess file content:
ErrorDocument 400 /error.php
ErrorDocument 401 /error.php
ErrorDocument 403 /error.php
ErrorDocument 404 /error.php
ErrorDocument 500 /error.php
ErrorDocument 503 /error.php
Page error.php:
<?php
$status = http_response_code();
switch ($status) {
case '400':
echo 'Custom error 400';
break;
case '404':
echo 'Custom error 404';
break;
...
}
Using GET param
ErrorDocument 400 /error.php?status=400
ErrorDocument 401 /error.php?status=401
ErrorDocument 403 /error.php?status=403
ErrorDocument 404 /error.php?status=404
ErrorDocument 500 /error.php?status=500
ErrorDocument 503 /error.php?status=503
Page error.php:
<?php
$status = empty($_GET['status']) ? NULL : $_GET['status'];
switch ($status) {
case '400':
echo 'Custom error 400';
break;
case '404':
echo 'Custom error 404';
break;
...
}
Related: How to enable mod_rewrite for Apache 2.2
If you need to have it display its default 404 page, before any output, do this:
header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
See here: http://www.php.net/manual/en/function.header.php
So, for your code, you could modify it to:
$page = 'examplePage.php';
$page404 = '404.php';
if (file_exists($page))
{
require($page);
}
else if (file_exists($page404))
{
require($page404);
}
else
{
header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found");
}
?>
Note the following warning that header stuff has to be done before any other output:
Remember that header() must be called before any actual output is
sent, either by normal HTML tags, blank lines in a file, or from PHP.
It is a very common error to read code with include, or require,
functions, or another file access function, and have spaces or empty
lines that are output before header() is called. The same problem
exists when using a single PHP/HTML file.
I asked similar question before a while ago
Access apache errordocument directive from PHP
Upshot was either redirect the user to a generic 404 page (so the address changes) Header("Location: $uri_404"); or curl your own 404 page and echo it, like so:
Header('Status: 404 Not Found');
$uri_404 = 'http://'
. $_SERVER['HTTP_HOST']
. ($_SERVER['HTTP_PORT'] ? (':' . $_SERVER['HTTP_PORT']) : '')
. '/was-nowhere-to-be-seen';
$curl_req = curl_init($uri);
curl_setopt($curl_req, CURLOPT_MUTE, true);
$body = curl_exec($curl_req);
print $body;
curl_close($curl_req);
Code credit to #RoUS
Maybe you could try:
header('HTTP/1.0 404 Not Found');
Im starting to devellop a pagination system, and so I´ll need to get some numbers in my URL, but Im having
one problem.
I have a project root folder "project", inside this folder I have:
1 .htaccess file
1 index.php file, that is where I call my getHome() function, to include the correct page and is where I import css, javascripts files, etc
1 folder with name "tpl", and inside it, I have my other index.php file that is my homepage and my other php files (categories.php, contacts.php,...)
To acess my homepage, Im using this url: localhost/project/
And now Im trying to get the numbers I pass in URL with this code:
$page = $url[1];
$page = ($page ? $page : 1);
echo '<h1>'.$page.'</h1>';
The problem is,
If I use this code to get number that I pass in URL in my "categories.php" file, like this: "htttp://localhost/projet/categories/2" -> it's working fine, I get echo of "2" and I have my categories.php file included, but wih one problem, I have some images im my categories.php file and if I use localhost/project/categories I have my images included correctly, but If I use localhost/project/categories/test-1 I can get value I pass in my url and my categories page is included but my images dont appear, images just appear in localhost/project/categories.
If I use this code to get number that I pass in URL in my "index.php" file, like this "htttp://localhost/project/2" Im getting my page 404 error "tpl/404.php", that I include in my getHome() function.
Do you see some way, using my function getHome(), how I can get the number I pass in url, using for example localhost/project/3, and have my index.php file included normally, and dont have my 404 page tpl/404.php' included?
And also how I can my solve my images problem with my categories page?
This is my function getHome()
function getHome(){
$url = $_GET['url'];
$url = explode('/', $url);
$url[0] = ($url[0] == NULL ? 'index' : $url[0]);
if(file_exists('tpl/'.$url[0].'.php'))
{
require_once('tpl/'.$url[0].'.php');
}
else
{
require_once('tpl/404.php');
}
}
This is my .htaccess file:
RewriteEngine OnRewriteCond %{SCRIPT_FILENAME} !-f
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ index.php?url=$1
Also, If I use index in my URL, like this: htttp://localhost/projet/index/2, it works, I can get my url value of "2" and I have my home page included correctly. But I´m trying to have just my htttp://localhost/project/2 and get the value I pass, in this case "2" with my homepage and not my 404 error page.
Try using array_pop to get the last value of url then check is_numeric
function getHome(){
$url = (isset($_GET['url'])) ? $_GET['url'] : $_SERVER['REQUEST_URI'];
$url = explode('/', $url);
$template = $url[0] == NULL ? 'index' : $url[0];
$last = array_pop($url);
$page = (is_numerica($last)) ? $last : 1;
if ($template == 'index') {
return $page;
}
if(file_exists("tpl/$template.php")) {
require_once("tpl/$template.php");
} else {
require_once('tpl/404.php');
}
}
$page = getHome(); // $page is used in index.php
Ok, am using traditional php, no frameworks, nothing, I am using simple procedural way, now my question is I was searching for a while but am not getting an answer to my question, I am not using .htaccess files as of now, but I really need to understand how 404 error works? I am having a website, where I show post's related to category, say category=php, so I pass this as a get request
$_GET['category'] == 'php';
Now currently what am doing is something like this :
$pocategory = $_GET['category'];
if($pocategory == 'php' || $pocategory == 'javascript') {
//Then show related posts
} else {
header('Location:404.php');
exit;
}
I mean I just want php and javascript as valid request's value, rest I want to redirect to 404 but am not understanding how to do it so I did this way, what if am having more than 50 categories? I cant list them all in this if condition, Inshort how to detect whether the given get request value is invalid or not..
Any help will be much appreciated.
.htaccess is the way to do this.
ErrorDocument 404 index.php?404
that line will tell apache what file to load. The example above calls the main index.php script.
add something like this to the top of your index.php file:
$error_404 = isset($_GET["404"]) ? true : false;
now you can detect if you have a 404 error request. $error_404 will be true, so why not add a simple function:
function error_404($error_404)
{
if($error_404 == true)
{
// do some error stuff here, like set headers, and some text to tell your visitor
}
}
now just call your function:
error_404($error_404);
best to do that immidiatley after the get handler:
error_404($error_404)
$error_404 = isset($_GET["404"]) ? true : false;
or combine the two into one line:
error_404($error_404 = isset($_GET["404"]) ? true : false);
to address the question, add this to the relevant script:
$pocategorys_ar = array("php","javascript");
if (!in_array($pocategory, $pocategorys_ar))
{
error_404(true);
}
Make sure it has access to the error_404() function.
You could put all categories inside an array like this:
$pocategories = array
(
'php',
'javascript'
);
if (in_array($pocategory, $pages))
{
// ...
}
else
{
header('Location:404.php');
}
Another thing you could do is creating a html/php file for every category and do it like so
if (is_file('sites/' . $popcategory . '.php')
{
include('sites/' . $popcategory . '.php');
}
else
{
header('Location:404.php');
}
Making a website and I want to put in a custom profile URL for all the users on my site (like facebook).
On my website already, people have a page like http://sitename.com/profile.php?id=100224232
However, I want to make a mirror for those pages that relates to their username. For example, if you go to http://sitename.com/profile.php?id=100224232 it redirects to you http://sitename.com/myprofile
How would I go about doing this with PHP and Apache?
No folders, no index.php
Just take a look at this tutorial.
Edit :
This is just a summary.
0) Context
I'll assume that we want the following URLs :
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);
}
To conclude
I wish I was clear enough. I know this code is not pretty, and not in an OOP style, but it could give some ideas...
I've been trying to get my sessions running across my subdomains, which I'm pretty sure I got working on Monday but after adding some code Tuesday its not working Wednesday! I've used the code ini_set("session.cookie_domain", $domain); where $domain = .example.com.
My site's main page is currently located on test.example.com and I access the login page through test.example.com/login. When i enter this address, the url in the address bar is automatically changed to http://www.test.example.com/login, and this is where the problem lies. The session is created for www.test.example.com but most links on the site direct to test.example.com/<sub folder>.
The only thing I can think of that might be throwing it off is the way I handle sessions. In every page a session is started. First the ini_set("session.cookie_domain", $domain); is set, then the session is started. Next I check to see if the session has expired. If the session has expired the current session is destroyed and unset then a new session is created. The rest is just setting up user information.
The only thing I've added recently is the session expiry checker. I've tried bypassing it but it hasn't changed anything.
Any help is greatly appreciated. I can post code if it makes it easier.
Mike
Please add some code :).
I can only tell you how we achieved the same functionality. Try adding
<directory "/path/to/your/docroot">
php_value session.cookie_domain ".example.com"
</directory>
to your virtual host configs. This was the only thing we had to do to make this functionality work. Now we can access all subdomains with the same cookies without adding all the extra code. I don't say this is a solutions, but this approach makes testing a lot less complicated.
Edit
You can set virtual hosts in the configuration of your webserver. Assuming you use apache they will be either in httpd.conf or are present in other files on the filesystem which are included in your httpd.conf. Where httpd.conf is located on your system depends on your configuration, but if you use Linux it will probably be somewhere in /etc/apache, /etc/httpd, /usr/local/apache, /usr/local/httpd
Once you have located this file it will have one or more entries like this:
<VirtualHost *:80>
ServerAdmin webmaster#yourdomain.org
DocumentRoot /var/www/yourdomain/www
ServerName yourdomain.org
<directory "/var/www/yourdomain/www">
Options FollowSymLinks Includes
AllowOverride All
Order allow,deny
Allow from all
</directory>
</VirtualHost>
And modify the code that it looks like this:
<VirtualHost *:80>
ServerAdmin webmaster#yourdomain.org
DocumentRoot /var/www/yourdomain/www
ServerName yourdomain.org
<directory "/var/www/yourdomain/www">
Options FollowSymLinks Includes
AllowOverride All
Order allow,deny
Allow from all
php_value session.cookie_domain ".yourdomain.org"
</directory>
</VirtualHost>
Notice the php_value session.cookie_domain ".yourdomain.org" line.
Add this line to all server configuration for this domain and your cookies will be shared.
This is impossible to debug without knowing more details.
You might want to first check if the cookies are being set properly, and if they are actually being returned to the server.
Use a tool which lets you see headers on your browser (webdeveloper toolbar / liveheaders / firebug for Firefox) and see if the server is actually requesting that the browser accept a cookie - and for what.
Forgive me for not knowing but what 'virtual host configs' is. My code runs something like this:
The main page will include session.php
function Session()
{
$this->time = time();
$this->startSession();
}
function startSession()
{
global $serverFunctions;
$serverFunctions->setSubdomainSharing();
session_start();
$this->checkSessionLife();
//check if user is logged in
$this->logged_in = $this->checkLogin();
//if user is not logged in then it is given guest credintials
if (!$this->logged_in)
{
$this->user_name = $_SESSION['user_name'] = GUEST_NAME;
$this->user_level = $_SESSION['user_level'] = GUEST_LEVEL;
}
if (!isset($_SESSION['language']))
{
$this->setLanguage("translation_english");
}
else
{
$this->user_language = $_SESSION['language'];
}
}
function checkSessionLife()
{
global $serverFunctions;
if (isset($_SESSION['start_time']))
{
$session_life = time() - $_SESSION['start_time'];
if ($session_life > 15)
{
$this->logout();
$serverFunctions->setSubdomainSharing();
session_start();
}
}
else if (!isset($_SESSION['start_time']))
{
//logout any session that was created
//before expiry was implemented
$this->logout();
$serverFunctions->setSubdomainSharing();
session_start();
}
$_SESSION['start_time'] = time();
}
function logout()
{
global $database;
// Unset session variables
session_destroy();
session_unset();
//session_regenerate_id(true);
$this->logged_in = false;
// Set user level to guest
$this->user_name = GUEST_NAME;
$this->user_level = GUEST_LEVEL;
}
The session file includes another PHP file called serverFunctions. This is just a class that allows me to format URL and such.
function getAddressPrefix()
{
$address_prefix = "";
if ($_SERVER['SERVER_ADDR'] == '127.0.0.1')
{
$address_prefix = "http://localhost/myproject";
}
else
{
$address_prefix = $this->getServerName();
}
return $address_prefix;
}
function getServerName()
{
return "http://" . str_replace("www.", "", $_SERVER['SERVER_NAME']);
}
function formatRequestingPage()
{
return $this->getServerName() . $_SERVER['SCRIPT_NAME'];
}
function setSubdomainSharing()
{
if ($_SERVER['SERVER_ADDR'] != '127.0.0.1')
{
$domain = $this->getServerName();
do
{
$domain = substr($domain, strpos($domain, ".", 0) + 1);
}
while (substr_count($domain, ".") > 1);
$domain = ".".$domain;
ini_set("session.cookie_domain", $domain);
}
}
When the user logs in, the login request is handled by process_request.php
function LoginReq()
{
global $session;
global $variables;
global $serverFunctions;
$retval = $session->login($_POST['user_name'], $_POST['password']);
if ($retval)
{
header("Location: " . $serverFunctions->getAddressPrefix());
exit();
}
else
{
$_SESSION['variables_array'] = $_POST;
$_SESSION['error_array'] = $variables->getErrorArray();
header("Location: " . $serverFunctions->getAddressPrefix() . "/login/");
exit();
}
}
If I'm missing anything or need to explain what happens a bit more let me know.