How to set header HTTP code in PHP without page terminate? - php

Can you please suggest me, how can I set 412 http code in header while coming invalid request from user form with out page termination or break.
Below code I am using in validation function
if(bad request){
header('HTTP/1.1 412 Precondition Failed', true, 412);
}
Note : only header should set the http code and page will return to user form and with error emssage
Validation function
function validateContactData($postData){
$db = &JFactory::getDBO();
$errorMsg = array();
$builder_name = $this->emptyReplace($postData['builder_name']);
if($builder_name == '' ){
header('HTTP/1.1 412 Precondition Failed', true, 412);
$errorMsg['builderNmError'] = "Please Select builder Program. ";
}
return $errorMsg;
}

I have found the solution which I used below function for set the header response without stuck the page .
http_response_code(412);

Related

Redirect and POST at the same time

I have a form and I don't do client-side validation other than required attribute. I'm doing the validation on the server side.
lyrics/add.php
<form action="../scripts/lyrics/submit_lyrics.php" id="lyricsForm" method="post" autocomplete="off" enctype="multipart/form-data">
Form data is processed in a seperate php file. Retrieving and validating the form data in the following way:
scripts/lyrics/submit_lyrics.php
$form_data = new FormData(["artist", "album", "song", "year", "track_no", "lyrics"], "sssiis");
$form_data->validate();
What the validate method does is
public function validate() {
$valid = $this->check_form_data($fields);
$fields = implode(",", $fields);
if (!$valid) {
header("location: ".BASE."lyrics/add?status=error&problem=input&specifics=$fields");
exit;
}
}
check the form data and redirect the page (scripts/lyrics/submit_lyrics.php) to the form page (lyrics/add.php) with the information on validation (if it failed). Then I output an error message indicating that there's something wrong with the input using GET method.
I'm curious if I can do this using POST. I would need to modify this line
header("location: ".BASE."lyrics/add?status=error&problem=input&specifics=$fields");
make it redirect the page to BASE."lyrics/add" and also send the validation information using POST to that page. So I'd still be able output the validation error, but using POST instead of GET.
Is this possible?
No, this is not possible because you are rewriting the request. The browser will always send a "GET" request in response to a redirect request, unless it receives a 307 request in which it will repeat the request using the same method and parameters. See this related question on Programmers.
The workaround is to redirect to a new page with an embedded form that you generate, and have javascript POST that form for the user. It's an extra request but it's the only way to have the client make a second POST.
Using u_mulder's suggesion (storing values in a session), I've solved the problem in the following way:
scripts/lyrics/submit_lyrics.php
public function validate() {
$valid = $this->check_form_data($fields); // check if input fields are valid
$fields = implode(";", $fields); // invalid input fields
if (!$valid) { // not all fields are valid, so we return
session_start(); // start session
if (!isset($_SESSION["problem"])) { // making sure session variable doesn't exist
$_SESSION["problem"] = "input"; // error type: input, file_upload, db_insert, etc.
$_SESSION["specifics"] = $fields; // artist, album, etc. (for input)
}
header("location: ".BASE."lyrics/add?status=error"); // redirect to form page
exit;
}
}
lyrics/add.php
if (isset($_GET["status"])) {
$status = $_GET["status"];
switch ($status) {
case "error":
session_start();
if (isset($_SESSION["problem"])) {
$problem = $_SESSION["problem"];
$specifics = explode(";", $_SESSION["specifics"]);
$error_message = "There was an error.";
switch ($problem) {
case "input":
$error_message = "Invalid input on the following fields:";
break;
// other cases ...
}
session_destroy();
output("Error!", $error_message, $specifics);
} else {
// if the user reloads the page, session data is lost
// but we're still in the error page "lyrics/add?status=error" and have no error to show
// we either show an appropriate message or redirect to "lyrics/add"
session_destroy();
// output("Error!", "You're in the form validation error page, but there aren't any errors. Did you reload the page?");
// header("location: ".BASE."lyrics/add");
// exit;
}
break;
case "success":
// form submitted successfully
break;
}
} else {
// show form
}

SLIM PHP api 400 error - $_REQUEST not working

I'm beginning to learn how to properly use REST API's following a popular tutorial here
When trying to create a simple POST api I keep running into a 400 error and I haven't found any answers online as of yet.
API is as follows:
$app->post('/test', function() use ($app) {
// check for required params
verifyRequiredParams(array('email'));
echo "Success";
});
Which attempts to verify the 'email' parameter with this block of code, unchanged from the tutorial:
function verifyRequiredParams($required_fields) {
$error = false;
$error_fields = "";
$request_params = array();
$request_params = $_REQUEST;
// Handling PUT request params
if ($_SERVER['REQUEST_METHOD'] == 'PUT') {
$app = \Slim\Slim::getInstance();
parse_str($app->request()->getBody(), $request_params);
}
foreach ($required_fields as $field) {
if (!isset($request_params[$field]) || strlen(trim($request_params[$field])) <= 0) {
$error = true;
$error_fields .= $field . ', ';
}
}
if ($error) {
// Required field(s) are missing or empty
// echo error json and stop the app
$response = array();
$app = \Slim\Slim::getInstance();
$response["error"] = true;
$response["message"] = 'Required field(s) ' . substr($error_fields, 0, -2) . ' is missing or empty';
echoRespnse(400, $response);
$app->stop();
}
}
The code always fails with a 400 error code because it seems that the $_REQUEST function is returning an empty array. Any idea's what could be going wrong? I'm developing on an ubuntu server running apache.
The Slim API framework is set up correctly as I can call a very simple call through Google's Advanced Rest Client which echos a response correctly. And I am definitely passing the correct parameters into the api.
UPDATE: I've also tried running the $_REQUEST and $_GET functions directly from the api and it just returns an empty string like this:
Array
(
)
I wonder if there's some sort of apache config file that's blocking data to these functions or something?
Possible Problem:
Have you double checked that your selected Content-Type in the request headers is right?
I suspect the client is perceiving a malformed markup language being sent from the server side.
Possible Solution:
Change Content-Type: application/x-www-form-urlencoded to application/JSON or vice versa.
For the tutorial to receive
$name = $app->request->post('name');
the POST parameters have to be in Payload data
name=yourname&password=pass&email=me#mail.com
application/x-www-form-urlencoded
If you provide the parameters after the URL but not in the payload data, that is for a GET request. In such a case the tutorial partly works (it sees the parameters to verify required parameters are present) but it is looking for the parameters "anywhere" when it should only be looking in the payload parameters for POST.

How to tell the browser to display his default error page?

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');

Unable to Simulate HTTP 302 response

I'm trying to incorporate PagSeguro (a payment gateway - Brazil's version of PayPal) into my site. After the customer finishes with PagSeguro, they send data (via POST) to a function which I specify. However, I'm not receiving the POST. After doing all the troubleshooting I could think of, I contacted PagSeguro. They said that their log indicates that the POST is being sent as normal but they are receiving an HTTP 302 response.
In order to figure out why this is happening, I created a form with hidden values to simulate sending a POST to my function. I put this form under a different domain just in case it had something to do with that. Every time I send the POST from my simulation form, I receive an HTTP 200 response, and my log indicates that the POST was received.
How is it possible that PagSeguro is receiving a different response than my simulation? Could it have something to do with the server or is it something to do with my script?
Here is the function (using CodeIgniter) that should be receiving the POST:
function pagseguro_retorno(){
if (count($_POST) == 0) {
return FALSE;
}
$msg = 'POST RECEIVED';
$simulate = $this->input->post('Simulate');
if ( ! empty($simulate)){
$result = 'VERIFICADO';
$msg .= ' FROM SIMULATOR';
} else {
$this->load->library(PagSeguroNpi);
$result = $this->PagSeguroNpi->notificationPost();
}
$this->log($msg);
if ($result == "VERIFICADO") {
$id = $this->input->post('Referencia');//cart id
$this->load->model('transacao_model');
$trans_row = $this->transacao_model->get_transaction($id);
if ( ! is_object($trans_row)){
//LOAD NEW TRANSACTION
if ( ! $this->new_transaction($id)){
$notice = "Unable to load new transaction</p><p>";
$this->log($notice);
$notice .= '<pre>'.print_r($_POST, TRUE).'</pre>';
$this->email_notice($notice);
}
}
$this->load->model('carrinho_model');
if($_POST['StatusTransacao'] == 'Aprovado'){
$status = 'apr';
}elseif($_POST['StatusTransacao'] == 'Em AnĂ¡lise'){
$status = 'anl';
}elseif($_POST['StatusTransacao'] == 'Aguardando Pagto'){
$status = 'wtg';
}elseif($_POST['StatusTransacao'] == 'Completo'){
$status = 'cmp';
//nothing more happens here - client must click on 'mark as shipped' before cart is removed and history data is loaded
}elseif($_POST['StatusTransacao'] == 'Cancelado'){
//reshelf - don't set $status, because the cart's about to be destroyed
$this->carrinho_model->reshelf(array($id));
}
if (isset($status)){
$this->carrinho_model->update_carrinho($id, array('status' => $status));
}
} else if ($result == "FALSO") {
$notice = "PagSeguro return was invalid.";
$this->log($notice);
$notice .= '<pre>'.print_r($_POST, TRUE).'</pre>';
$this->email_notice($notice);
} else {
$notice = "Error in PagSeguro request";
$this->log($notice);
$notice .= '<pre>'.print_r($_POST, TRUE).'</pre>';
$this->email_notice($notice);
}
}
SECURITY UPDATE:
After posting, I soon realized that I was opening myself up to hack attempts. The function necessarily has to be public, so anyone who knows the name of the function could access it and post 'simulate' to get immediate verification. Then they could pass whatever data they wanted.
I changed the name of the function to something that would be impossible to guess, and when not in production mode, I've disabled the simulate option.
The problem was that my CSRF protection causes a redirect when the proper CSRF code isn't sent with the POST. My simulator was working, because I copied the HTML generated by a dynamic simulator that I made on the site in question. I then pasted the HTML to create a static simulator and put it under a different URL. Along with the HTML, I inadvertently pasted the CSRF code as well. The static simulator worked fine until the code expired. I quit using it after a couple times, so I didn't discover that it was no longer working until today.
I know that this exact scenario probably won't happen again in the next 500 years, but things like CSRF security can cause problems with things like payment gateways if not disabled for the function receiving the POST.

Display unauthorised page when user clicks 'cancel' (html/php)

I've recently started learning html and php. I'd appreciate it if someone could point me in the right direction: I've made a basic webpage that has basic authentication (to enter it). When the user clicks the cancel button, I would like the browser to do something! All it does is, remain on the page it was on (before the user attempted to access my page). I guess I would like it to display the 401 error. Is the only way to do this, to insert text after:
header('www-authenticate: basic');
?
I've tried redirecting 401 errors in the .htaccess file, though it would seem that the 401 error never occurs (although the server access log says that there was a 401 error). When I redirected my 404 error using .htaccess, it worked.
This is the code that I've got for the authentication:
<?php
$user = array('Michael' => 'Mike');
$pass = array('Michael' => 'fish');
$userSuccess = false;
$passSuccess = false;
if(!isset($_SERVER['PHP_AUTH_USER']) && !isset($_SERVER['PHP_AUTH_PW']))
{
header('http/1.1 401 Unauthorized');
header('www-authenticate: basic');
exit;
}
else
{
foreach($user as $value)
if($_SERVER['PHP_AUTH_USER'] == $value)
$userSuccess = true;
foreach($pass as $value)
if($_SERVER['PHP_AUTH_PW'] == $value)
$passSuccess = true;
if(!$userSuccess || !$passSuccess)
{
header('http/1.1 401 Unauthorized');
header('www-authenticate: basic');
exit;
}
}
?>
Also, if I've done anything stupid in my code, feel free to point it out.
I thought that since I sent the 401 header to the server, and the server logged having received it, it would've displayed some text say, 'Error 401: Unauthorised Access' or something along those lines.
Thanks.
you need to serve the browser with the content for 401. This is not done automatically. The 401 header you send is never really seen by the user. Think of it more as a status flag than content. Programs use that header to detect certain issues and act upon them (i.e. a download manager may detect the 404 header which then shows the download line in its window with a red background and error symbol).
In conclusion then, you need to print the error to the browser yourself
You're going on the right way. I'll do just some changes on your code:
$user = array('Mike' => array('Michael', 'fish'));
if(!isset($_SERVER['PHP_AUTH_USER']) && !isset($_SERVER['PHP_AUTH_PW']))
{
header('http/1.1 401 Unauthorized');
header('www-authenticate: basic');
exit;
}
else
{
$input_user = $_SERVER['PHP_AUTH_USER'];
$input_pw = $_SERVER['PHP_AUTH_PW'];
if($user[$input_user][1] != $input_pw)
{
header('http/1.1 401 Unauthorized');
header('www-authenticate: basic');
exit;
}
}
echo "Hi, " . $user[$input_user][0];
First of all I've changed your users array layout on this layout to this:
Array
(
[Mike] => Array
(
[0] => Michael
[1] => fish
)
)
Read for further info Multidimensional Arrays.
Secund, is your username, then it will have another array with name and password of the user. So you'll not have to user foreach to match your username and pass. BTW, the way you done before your script will allow any user to access with another users pass. If you have other user foo and try user = foo and pass = fish it will gain the access.
Third thing is that you don't need to use $userSuccess and $passSuccess no more. Just to decrease code lenght.
Then I associate two vars to the _SERVER vars, to make easy their use. So you can match then with this sentence: $user[$input_user][1] != $input_pw.
I hope this can helps you.

Categories