I have an HTML page that sends a JQuery Ajax call to a PHP page and is expecting a JSON response. If the PHP has a parser error, the error is returned to the call, but not in JSON format, so it ends up throwing a "JSON.parse: unexpected character" error on the Ajax side.
Is there a way to get the PHP to send the error message back in a JSON-friendly format? (Yes, it sends the error to event.log in the PHP file's directory, but I'd rather not have to jump through the hoops of accessing it each time there's a problem with the script.)
Edit: Somebody asked for the code - what I mean is, something like this:
First, the "bad" PHP script, oops.php:
<?php
$x = "There's no terminating semicolon"
echo json_encode($x);
?>
Now, the HTML page that calls it, oops.html:
<html>
<head><title>OOPS</title></head>
<body>
<div id="text_goes_here"></div>
</body>
<script>
var $outputText = "Text goes here";
$.ajax({
url:"oops.php",
type:"GET",
data: {},
success:function(data) {
outputText = "Success:<br />";
for (var d in data) {
outputText += (data[d] + "<br />");
}
document.getElementById("text_goes_here").innerHTML = outputText;
},
error:function(xhr, status, message) {
outputText = "Error:<br />";
+ "Status: " + status + "<br />"
+ "Message: " + message + <br />";
document.getElementById("text_goes_here").innerHTML = outputText;
},
dataType:"json"
});
</script>
</html>
The problem appears to be, the PHP returns an error message, but not in a JSON format, so the .ajax call's JSON parser doesn't understand what it is and throws an error of its own. I want to be able to pass the script error that the PHP script generated back to the call in a format that the call can read.
Use try-catch block.
This article shows how to write a AJAX handler with exceptions handled.
Here's the PHP code.
<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/inc/ajax.inc.php';
try {
if ($_SERVER['REQUEST_METHOD'] !== "POST") {
throw new Exception('Invalid Request', 2000);
} else {
// status is true if everything is fine
exit(json_encode(
array(
'status' => true
)
));
}
} catch(Exception $e) {
echo json_encode(
array(
'status' => false,
'error' => $e -> getMessage(),
'error_code' => $e -> getCode()
)
);
exit;
}
And, the JS code:
function jsonParse() {
try {
var json = JSON.parse(text);
}
catch(e) {
return false;
}
return json;
}
var http = new XMLHttpRequest();
var data = "username=" + name + '&email=' + email;
http.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
var json = jsonParse(this.responseText);
if (!json || json.status !== true) {
console.log(json.error || 'Something Bad Happened');
return;
}
alert('Everything is Fine!');
}
}
http.open('ajax.php', 'POST', true);
http.send(data);
Thanks.
Related
I am able to consume the php endpoint from postman. I try to do the same from angular post, I get this error - Http failure during parsing for. Even though everything looks perfect to me, the problem is surprising. Here is my snippet
php file
<?php
header('Access-Control-Allow-Origin: *');
// check for post
if ($_SERVER['REQUEST_METHOD']=='POST') {
$name = $_POST['name'];
$email = $_POST['email'];
$subject = $_POST['subject'];
$message = $_POST['message'];
// include db connect class
require_once __DIR__ . '/db_connect.php';
// connecting to db
$conn = new db_CONNECT();
$cone=$conn->con;
//escpae the strings to be inserted to DB
$escapedname = mysqli_real_escape_string($cone, $name);
$escapedemail = mysqli_real_escape_string($cone, $email);
$escapedsubject= mysqli_real_escape_string($cone, $subject);
$escapedmessage = mysqli_real_escape_string($cone, $message);
// mysql inserting a new row
$sql = "INSERT INTO contacts(name, email, subject, message) VALUES ('$escapedname', '$escapedemail', '$escapedsubject', '$escapedmessage')";
// $result= $cone -> query($sql);
// $affected = $cone -> affected_rows;
if (mysqli_query($cone,$sql)) {
echo "Information saved successfully.";
} else {
echo "Not successful";
}
} else {
echo "Some field missing.";
}
?>
here is the angular snippet
saveContactDetails = function () {
this.proceed = true;
this.success = false;
const myheader = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
data.append('name', this.contactDeJson.name);
data.append('email', this.contactDeJson.email);
data.append('subject', this.contactDeJson.subject);
data.append('message', this.contactDeJson.message);
this.http
.post('http://localhost:80/'+'api/create_contact.php', data.toString(), {headers: myheader})
Please why am I getting this error
{"headers":{"normalizedNames":{},"lazyUpdate":null},"status":200,"statusText":"OK","url":"http://localhost/api/create_contact.php","ok":false,"name":"HttpErrorResponse","message":"Http failure during parsing for http://localhost/api/create_contact.php",
I believe the issue is that your angular script is expecting a json response (the default responseType), but not receiving the correct headers or data. In stead of just echoing out your result in php, I would make a function that can handle sending the response. Something like this:
function sendJsonResponse(data, status = 200) {
header('Content-Type: application/json', true, status);
echo json_encode($data);
exit();
}
In stead of of doing this:
echo "Not successful";
You can now do this:
sendJsonResponse("Not successful", 500);
This should give you more valuable information in the frontend. And the response should now be formatted correctly, and no longer produce the parse error in angular that you are getting now.
I believe you are trying to send some query parameters using data variable. You could actually send a JS object as the parameters. Try the following
private saveContactDetails() {
this.proceed = true;
this.success = false;
const myheader = new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded');
const data = {
'name': this.contactDeJson.name,
'email': this.contactDeJson.email,
'subject': this.contactDeJson.subject,
'message': this.contactDeJson.message
}
this.http.post('http://localhost:80/'+'api/create_contact.php', { params: data }, { headers: myheader })
}
I've tried many examples posted online about uploading images via Nativescript (this part I seem to be getting right bar one or two issues), but my PHP server isn't responding with anything and I don't know how to access the file being uploaded to the server as nowhere in the upload data is the file name mentioned from what I can see. I'm using the background-http plugin, but have a few issues in general, namely:
- Where do I include user data in the image upload to the server using background-http?
- The completed handler on background-http doesn't receive the response from my server, it remains and empty object.
- On the server side, I'm struggling to pick up the file and have no idea how to receive the user data too.
What I'm asking for:
Does anyone have a working example of uploading from Nativescript Core using the Background-http plugin (and submitting user data along with the image), through to the PHP file that will receive it and process it and provide response? For the life of me I can't get it working.
I've tried the Background-http plugin example to the tee, it shows it's uploading but never shows the server response, just shows the responseCode of 200.
On the server side, I have tried many examples I've found online, but none seem to be working - I suspect this is because they are mostly web examples. I need something specific to Nativescript.
Nativescript JS file
exports.uploadImage = () => {
// file path and url
var file = cameraViewModel.imageAsset;
var url = "https://www.wesignit.co.za/api/wsi_1/WSI_1_PROD/image_upload.php";
var name = file.substr(file.lastIndexOf("/") + 1); //this gets the filename
// upload configuration
var bghttp = require("nativescript-background-http");
var session = bghttp.session("image-upload");
var request = {
url: url,
method: "POST",
headers: {
"Content-Type": "application/octet-stream"
},
description: "Uploading file: " + name
};
var task = session.uploadFile(file, request);
task.on("progress", progressHandler);
task.on("error", errorHandler);
task.on("responded", respondedHandler);
task.on("complete", completeHandler);
// event arguments:
// task: Task
// currentBytes: number
// totalBytes: number
function progressHandler(e) {
cameraViewModel.uploadOutputs = "Uploading file: " + name + " - uploaded " + e.currentBytes + " / " + e.totalBytes + "(" + (Math.round(e.currentBytes/e.totalBytes * 100) * 10 / 10) + "%)";
}
// event arguments:
// task: Task
// responseCode: number
// error: java.lang.Exception (Android) / NSError (iOS)
// response: net.gotev.uploadservice.ServerResponse (Android) / NSHTTPURLResponse (iOS)
function errorHandler(e) {
cameraViewModel.uploadOutputs = "received " + e.responseCode + " code.";
//cameraViewModel.uploadOutputs = "Error uploading file - try again!";
//var serverResponse = e.response;
//alert(e.response);
alert("Error uploading file - try again!");
}
// event arguments:
// task: Task
// responseCode: number
// data: string
function respondedHandler(e) {
cameraViewModel.uploadOutputs = "received " + e.responseCode + " code. Server sent: " + e.data;
}
// event arguments:
// task: Task
// responseCode: number
// response: net.gotev.uploadservice.ServerResponse (Android) / NSHTTPURLResponse (iOS)
function completeHandler(e) {
cameraViewModel.uploadOutputs = "received " + e.responseCode + " code";
var serverResponse = e.response;
alert(JSON.stringify(e));
}
}
PHP upload file
header('Content-Type: application/json; charset=utf-8');
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: PUT, GET, POST");
$response = array();
$upload_dir = 'uploads/';
$server_url = 'https://www.wesignit.co.za';
if($_FILES['avatar'])
{
$avatar_name = $_FILES["file"]["name"];
$avatar_tmp_name = $_FILES["file"]["tmp_name"];
$error = $_FILES["file"]["error"];
if($error > 0){
$response = array(
"status" => "error",
"error" => true,
"message" => "Error uploading the file!"
);
}else
{
$random_name = rand(1000,1000000)."-".$avatar_name;
$upload_name = $upload_dir.strtolower($random_name);
$upload_name = preg_replace('/\s+/', '-', $upload_name);
if(move_uploaded_file($avatar_tmp_name , $upload_name)) {
$response = array(
"status" => "success",
"error" => false,
"message" => "File uploaded successfully",
"url" => $server_url."/".$upload_name
);
}else
{
$response = array(
"status" => "error",
"error" => true,
"message" => "Error uploading the file!"
);
}
}
}else{
$response = array(
"status" => "error",
"error" => true,
"message" => "No file was sent!"
);
}
echo json_encode($response);
I expect to see a server response, even if just a dummy response object (which I've also tried), but am only receiving responseStatus, responseCode etc.... The response object which I expect to be populated is empty.
On the server: it's clear that the server is not receiving the file and processing it.
Please help. I'm struggling here. I just need a working example that I can copy going forward.
I have an api which sends arabic string data and needs to display in html web form using jquery $.ajax method but unfortunately ajax receives only a single character i.e 'a' in response as shown below
{code: 200, status: "error", msg: "a", msg_en: "Invalid Username!!"}
but when i execute the api in postman it shows me this
{"code":200,"status":"error","msg":"اسم المستخدم موجود بالفعل","msg_en":"Username already exists!!"}
this is my code in check_user_name.php
<?php
require_once "../admin/utils/config.php";
require_once "../admin/utils/dbClass.php";
$objDB = new MySQLCN;
require_once "../admin/utils/functions.php";
$fun = new mFunctions;
require_once "lang.confg.php";
$response = array();
if( isset($_POST['user_name']) && $_POST['user_name'] != null){
$user = $objDB->_get_user(null,$_POST['user_name'],null,null,null,null,array('visitor','lawyer','admin'));
if( !empty($user) ){
$response['code'] = 200; // successfull request
$response['status'] = 'error';
$response['msg'] = $_lang['user_name_exists'];
$response['msg_en'] = 'Username already exists!!';
}else{
$response['code'] = 200; // successfull request
$response['status'] = 'success';
$response['msg'] = $_lang['user_name_available'];
$response['msg_en'] = 'Username available!!';
}
}else{
$response['code'] = 200; // invalid paramters
$response['status'] = 'error';
$response['msg'] = $_lang['invalid_requests'];
$response['msg_en'] = 'Invalid Username!!';
}
end:
echo json_encode($response);
exit();
this is ajax request
$(document).on("change", 'input[name=user_name]', function(e) {
/* Act on the event */
var user_name = $ (this).val();
if(user_name.length >= 6 || !user_name.length <=1 ){
$.ajax({
type: 'POST',
url: HOST_URL_API+'/check_user_name.php',
dataType: "json",
contentType: "application/json; charset=utf-8",
data : { 'user_name':user_name }, // our data object
success: function(data) {
console.log(data);
if (data.status == "error") {
$('input[name=user_name]').parent().addClass('has-error');
$('input[name=user_name]').parent().find('.help-block').html(data.msg);
$('input[name=user_name]').focus();
// alert(data.msg);
}else{
$('input[name=user_name]').parent().removeClass('has-error');
$('input[name=user_name]').parent().addClass('has-success');
$('input[name=user_name]').parent().find('.help-block').html('');
}
},
error: function(jqXHR, textStatus, errorThrown, data) {
alert(errorThrown);
},
});
event.preventDefault();
}else{
// alert("Username must be at least 6 characters");
}
});
kindly please if anyone have the solution, will be great help , thanks in advance ;)
Try adding below line in php code which may solve issue while rendering unicode characters.
header("Content-Type : application/json; charset=ISO-8859-1");
Please check this solution hope this will solve your problem i simple create index.php and run this i include header("Content-type: application/json; charset=ISO-8859-1"); this solve the problem.
if (isset($_GET['dataa'])) {
$res['code'] =200;
$res['status'] = 'error';
$res['msg'] = (string) "اسم المستخدم موجود بالفعل";
$res['msg_en'] = 'Username already exists!!';
// header ("Content-Type: text/html; charset=utf-8");
header("Content-type: application/json; charset=ISO-8859-1");
echo json_encode($res);die;
}
in same page html and get req for test resonse and append text to body
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
</head>
<body>
<script type="text/javascript">
$(document).ready(function(){
$.ajax({
url: "index.php",
type: 'GET',
data : {dataa : 'ss'},
success: function(res) {
console.log(res);
$('body').append(res.msg);
}
});
})
</script>
</body>
</html>
cheers good luck
Problem is solved guys, thanks for your efforts , actually it was the code mistake, there is an another array with same key name was replacing the array key's value, still thanks for your all efforts.
I am trying to retrieve data from AngularJS file to PHP file, but I get the error that it's empty.
I can't find any good examples that are dealing with posting data from angularJS to php file and so I need help.
Angularjs file:
angular.module('myApp', ['ajoslin.promise-tracker'])
.controller('help', function ($scope, $http, $log, promiseTracker, $timeout) {
$scope.ph_numbr =/[0-9]+/;
// Form submit handler.
$scope.submit = function(form) {
// Trigger validation flag.
$scope.submitted = true;
// If form is invalid, return and let AngularJS show validation errors.
if (!$scope.toggle || $scope.toggle.length <= 0 || form.$invalid) {
return;
}
// Default values for the request.
$scope.progress = promiseTracker('progress');
var config = {
params : {
//'callback' : 'JSON_CALLBACK',
'name' : $scope.name,
'email' : $scope.email,
'toggle' : $scope.toggle,
'phone' : $scope.phone,
'comments' : $scope.comments
},
tracker : 'progress'
};
$http({
method : 'POST',
url : 'js/contact.php',
data: config,
headers : {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}
})
.success(function(data, status, headers, config) {
if (data.success) {
$scope.name = null;
$scope.email = null;
$scope.toggle = null;
$scope.phone = null;
$scope.comments = null;
$scope.messages = 'Your form has been sent!';
$scope.submitted = false;
} else {
$scope.messages = 'Oops, we received your request, but there was an error processing it.';
$log.error(data);
}
})
.error(function(data, status, headers, config) {
$scope.progress = data;
$scope.messages = 'There was a network error. Try again later.';
$log.error(data);
});
// Hide the status message which was set above after 3 seconds.
var promise = $timeout(function() {
$scope.messages = null;
}, 3000);
$scope.progress.addPromise(promise);
};
});
php file:
<?php
/*error_reporting(E_ALL);
ini_set('display_errors', '1');
require_once 'js/PHPMailerAutoload.php';*/
ini_set('display_errors', 'On');
error_reporting(E_ALL | E_STRICT);
$data = file_get_contents("php://input");
$postData = json_decode($data);
if (isset($_POST['name']) && isset($_POST['email']) && isset($_POST['toggle']) && isset($_POST['comments'])) {
//check if any of the inputs are empty
if (empty($_POST['name']) || empty($_POST['email']) || empty($_POST['toggle']) || empty($_POST['comments'])) {
$data = array('success' => false, 'message' => 'Please fill out the form completely.');
echo json_encode($data);
exit;
}
$email = trim($_POST['email']);
$subject = trim($_POST['toggle']);
//email address settings
$my_address = "*#yahoo.com";
$headers = "From: ".$email;
$message = "Name: " . $_POST['name'] . "\r\n\r\nMessage: " . $_POST["phone"] . "\r\n\r\nMessage: " . stripslashes($_POST['comments']);
$to = $my_address;
if (isset($_POST['ref'])) {
$mail->Body .= "\r\n\r\nRef: " . $_POST['ref'];
}
if(!$mail->send()) {
$data = array('success' => false, 'message' => 'Message could not be sent. Mailer Error: ' . $mail->ErrorInfo);
echo json_encode($data);
exit;
}
mail($to, $subject, $message, $headers);
$data = array('success' => true, 'message' => 'Thanks! We have received your message.');
echo json_encode($data);
} else {
$data = array('success' => false, 'message' => 'Please fill out the form completely.');
echo json_encode($data);
}
?>
The error message that I get is: "Please fill out the form completely" - which means it doesn't get the values.
My other question is how in the AngularJS do I retrieve the data.success value from the php file?
You seem to be getting the data here:
$data = file_get_contents("php://input");
$postData = json_decode($data);
but then you're using $_POST instead. Perhaps this would work:
if (empty($postData['name']) //etc
It looks like you're accessing data.success appropriately and the value should be set to false as your code currently is.
Additional code review:
If there are errors on the server, it's best to return a status code that indicates that. As is, the server is returning 200 (default), which means everything is OK, even though the request is actually failing. That would eliminate the need for data.success. If the server sends status 200, your .success function will fire. If it returns an error status, like 404, then your .error function would fire instead.
I have doubts about your need of the Content-Type header. You might want to reconsider if that's necessary.
On your Angular form, you ought to nest those $scope properties in an object:
$scope.formData = {
name: '',
email: '',
//etc
}
Then, you can simply pass that directly to your $http call and to reset the values you can simply do $scope.formData = {}.
[Context]
This is Node js code from my local machine, works fine on live with changed host name. I use forever to execute it. Also php code which connects to node js server for http response. The above combinations works fine largely on production.
Problem: Once in 3-4 days, node js connectivity fails which results in down time for my application. It returns http code 0. Since I am using forever, it automatically connects back after 5-7 minutes but it is visibly painful during this interval. Specially on production. Can anybody suggest me potential area to debug or any working solution?
[Context]
var config = require('./config.js'),
http = require('http'),
redis = require('redis'),
redisClient = redis.createClient(config.redis.port,config.redis.host),
url = require('url'),
crypto = require('crypto');
var app = http.createServer(function (req, res) {
if(req.method == "OPTIONS"){
res.header('Access-Control-Allow-Origin', '*:*');
res.send(200);
} else {
var u = url.parse(req.url,true),
body = '';
req.on('data',function(chunk) {
body += chunk;
});
req.on('end',function() {
if(body) {
var data =JSON.parse(body);
if(data.__app_secret__ && data.__app_secret__ == '12345') {
switch(u.pathname) {
case '/generateusersecret' :
redisClient.get(req.headers.host + '_' + data.user_id,function(err,reply) {
if(reply) {
jsonResponse(res,{userSecret : reply});
} else {
genToken(req.headers.host + '_' + data.user_id,res);
}
});
break;
case '/getusersecret' :
redisClient.get(req.headers.host + '_' + data.user_id,function(err,reply) {
jsonResponse(res,{userSecret : reply});
});
break;
case '/publish':
redisClient.publish(data.channel,data.message);
jsonResponse(res,{});
break;
default :
jsonResponse(res,{error : "Unknown Command: " + u.pathname});
break
}
} else {
res.writeHead(403, {'Content-Type': 'text/plain'});
res.end('Not authorized');
}
}
});
}
});
//app.listen(config.port || 4000, "127.0.0.1");
app.listen(6006, 'myproductionurl.com');`enter code here`
console.log('Server running at http://myproductionurl.com:6006/');
var io = require('socket.io').listen(app,{
'origins' : "*:*"
}),
sockets = {};
/*
var io = require('socket.io').listen(6006);
var sockets = {};
*/
io.configure(function() {
// set authorization
io.set('authorization',function(handshakeData,callback) {
if(handshakeData.query.secret) {
// when the user's secret is in redis then we trust him as an authenticated user
if(redisClient.get(handshakeData.query.secret)) {
callback(null,true);
} else {
// unauthenticated user
callback(null,false);
}
} else {
// no secret were given
callback('Bad URL');
}
});
});
// #TODO: create separeta namespaces as: /notificaions, /chat etc...
io.sockets.on('connection',function(socket) {
var secret = socket.manager.handshaken[socket.id].query.secret,
_redisClient = redis.createClient(config.redis.port,config.redis.host);
// when the redis client gets a message from the subscribed channels, we are sending back to the user's browser via socket.io
_redisClient.on('message',function(channel,message) {
socket.emit('notification',JSON.parse(message));
});
// subscribe to the user's own channel
_redisClient.subscribe(secret);
// subscribe to the broadcast channel
_redisClient.subscribe('broadcast');
// TODO: subscribe to group channels (a.k.a rooms)
});
function jsonResponse(res,obj) {
res.writeHead(200, {'Content-Type': 'application/json'});
res.end(JSON.stringify(obj));
}
function genToken(prefix,res) {
crypto.randomBytes(48,function(ex,buf) {
var token = buf.toString('base64').replace(/\//g,'_').replace(/\+/g,'-');
redisClient.get(token,function(err,reply) {
if(reply) {
genToken(prefix,res);
} else {
redisClient.set(prefix,token);
jsonResponse(res,{userSecret : token});
}
});
});
}
private function api($url,$data) {
$ch = curl_init();
$data['__app_secret__'] = $this->appSecret;
curl_setopt($ch,CURLOPT_URL, $this->apiUrl.$url);
curl_setopt($ch,CURLOPT_POSTFIELDS, CJSON::encode($data));
curl_setopt($ch,CURLOPT_RETURNTRANSFER, 1);
$response = curl_exec($ch);
$responseHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
if($responseHttpCode == 403) {
throw new CException('Your app secret is not valid');
} elseif($responseHttpCode == 200) {
// nop
} else {
throw new CException('Uknown Error: ' . $responseHttpCode );
}
//close connection
curl_close($ch);
return CJSON::decode($response);
}