Unexpected token < in jquery ajax call for PHP - php

I am having jquery ajax call as follows.
$("form.form-signin").submit(function (e) {
e.preventDefault();
var $form = $(this);
$.ajax({
url : "scripts/logincontroller.php",
type: "POST",
dataType :"json",
data: {
username : $form.find("input[name='username']").val(),
password : $form.find("input[name='password']").val()
},
success: function(response){
$("div.jumbotron div#error_panel").css("display","block");
var err_msg = '';
if(response.errors != null){
for(i = 0; i<response.errors.length;i++){
err_msg += response.errors[i]+"</br>";
}
$("div.jumbotron div#error_panel div#message").empty().append(err_msg);
return;
}else{
$("div.jumbotron div#error_panel div#message").empty().append("ok");
}
},
error: function(xhr, status, errorThrown){
alert(errorThrown+status);
$("div.jumbotron div#error_panel").css("display","block");
}
});
});
Now I have following classes.
This class connects to database and returns db object if success, string error otherwise.
//DBConfiguration.class.php
namespace db;
class DBC{
const username = "root";
const password = "****";
const host = "localhost";
const schema = "mydb";
static function connect(){
try{
$dbh = new \PDO('mysql:host='.self::host.';dbname='.self::schema, self::username, self::password, array(
\PDO::ATTR_PERSISTENT => true
));
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $dbh;
}catch (\PDOException $e){
return "Failed to connect to database";
}
}
}
This class calls the above connect and returns the result.
//Authenticator.php
namespace db;
include "DBConfiguration.class.php";
class Authenticator{
public function isValidUser($username,$password){
$result = array();
$dbh = DBC::connect();
if(is_string($dbh) && $dbh === "Failed to connect to database"){
$err = array();
$err[] = "Oops! Something went wrong. We are working on it";
$result["errors"] = $err;
}else{
$err = array();
$err[] = "connected successfully";
$result["errors"] = $err;
}
return $result;
}
}
//LOGINCONTROLLER.PHP
header("Content-Type: application/json", true);
include "db\Authenticator.php";
$authenticator = new \db\Authenticator();
echo json_encode($authenticator ->isValidUser($_POST["username"],$_POST["password"]));
When I am intentionally changing the password and could not connect to db I am getting correct error message. But when it is successful (in which case I am returning db object from connect() method), I am getting 'unexpected token <'.
Weird thing is I am able to run the code when I place all these classes in logincontroller.php instead of induvidual namespaces.
Is there any problem with this code?

I found the answer. The following line is causing the problem.
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
The above line of code must be
$dbh->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
As I am calling this from a namespaced class PDO must refer to global PDO class.

Related

Endpoint can't make a POST request properly in PHP using SLIM framework

I'm trying to make a API server that is supposed to connect to a data base, using SLIM framework following this tutorial. Actually I made a endpoint who get data from the data base, but can't insert new one.
Every time when I try to insert new data the POST parameters are nulls and the data base only send a error message.
In my groupes.php I have the following:
<?php
use Slim\Http\Request;
use Slim\Http\Response;
// Routes
$app->get('/[{name}]', function (Request $request, Response $response, array$args) {
// Sample log message
$this->logger->info("Slim-Skeleton '/' route");
// Render index view
return $this->renderer->render($response, 'index.phtml', $args);
});
$app->group('/api', function () use ($app) {
$app->group('/v1', function () use ($app) {
$app->get('/clients', 'getClients');
$app->post('/make', 'addClient');
});
});
The code above is just to define two endpoits: getClients and addClient.
And in my index.php I have:
function getConnection(){
$dbhost = "127.0.0.1";
$dbuser = "root";
$dbpass = "dzpga883yRusPHhv";
$dbname = "pruebaandroid";
$dbh = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $dbh;
}
//method: GET
//domain: mi-api/api/v1/clients
function getClients($response){
$sql = "SELECT * FROM cliente";
try{
$stmt = getConnection()->query($sql);
$client = $stmt->fetchAll(PDO::FETCH_OBJ);
$db = null;
return json_encode($client);
}
catch(PDOException $e){
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
//method: POST
//domain: mi-api/api/v1/make
function addClient($request) {
$client = json_decode($request->getBody());
$sql = 'INSERT INTO cliente (nombre, apellido, cedula, direccion, telefono, email) VALUES (:nombre, :apellido, :cedula, :direccion, :telefono, :email)';
try {
$db = getConnection();
$stmt = $db->prepare($sql);
$stmt->bindParam(":nombre", $client->nombre);
$stmt->bindParam(":apellido", $client->apellido);
$stmt->bindParam(":cedula", $client->cedula);
$stmt->bindParam(":direccion", $client->direccion);
$stmt->bindParam(":telefono", $client->telefono);
$stmt->bindParam(":email", $client->email);
$stmt->execute();
$client->id = $db->lastInsertId();
$db = null;
echo json_encode($client);
}
catch(PDOException $e){
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
So, using postman to do a GET request to mi-api/api/v1/clientes retrieve all the data as spected, but whhen I try with a POST request mi-api/api/v1/make?nombre=asdf&apellido=asdf&cedula=asdf&direccion=asdf&telefono=asdf&email=asdf it's supposed to insert the new information but postman give me the following error:
{"error":{"text":SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'nombre' cannot be null}}
Looks like the addClient function it's not geting the parameters, so it's taking it as null. Why is this happening? I don't know what is wrong here, any response is welcome.
See the image
PD: yes, the DB is well formated, it have a id as PK auto increment and I tryed to print echo client->nombre and prints nothing but the error.
You are adding your parameters as GET parameters (added on url).
Use the BODY -> form-data tab to specify your POST parameters (The same you have in PARAMS tab)

Angular 6 and PHP SyntaxError: Unexpected token < in JSON at position 0 at JSON.parse (<anonymous>)

I have the following PHP class:
<?php
//header('Access-Control-Allow-Headers: *');
//header('Content-Type: application/json');
//header('Access-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS');
error_reporting(E_ALL);
class api {
private $username ="root";
private $password ="...";
private $db="...";
private $host = "localhost";
public $conn;
//Connection
public function connection(){
try{
$this->conn = new PDO("mysql:host=$this->host;dbname=$this->db", $this->username, $this->password);
$this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->conn->exec("SET CHARACTER SET utf8");
return $this->conn;
}
catch(PDOException $e){
return $e->getMessage();
}
}
//Login
public function login($conn, $user){
$login = "SELECT username FROM login WHERE username=:user LIMIT 1";
$execLogin = $this->conn->prepare($login);
$execLogin->bindValue(":user", $user);
$execLogin->execute();
$res = $execLogin->rowCount();
return $res;
// if($res>0)
// {
// return json_encode($res);
// }
// else{
// echo 0;
// }
}
}
?>
In this class, I have 2 main functions, the first to connect to the server, and the other is for logging in.
Then, in an Angular web app, if a user added his credentials, they will be sent to the login.php script through HttpClient of Angular 6:
<?php
//header('Access-Control-Allow-Headers: *');
header('Content-Type: application/json');
require_once('../api.php');
//Getting username and password from Angular
$user="brital";
//$pass = json_decode($_POST['credentials']);
$newApi = new api();
$conn = $newApi->connection();
$res = $newApi->login($conn, $user);
echo json_encode($res);
?>
As for the angular script, I created an angular service as an API file to manage all methods related to server connection.
import { Injectable } from '#angular/core';
import { HttpClient, HttpHeaders } from '#angular/common/http';
import { map } from 'rxjs/operators';
#Injectable({
providedIn: 'root'
})
export class AuthApiService {
public credentials:any=[];
constructor(private http: HttpClient) { }
login(username, password)
{
let headerOptions = new HttpHeaders();
headerOptions.append('Access-Control-Allow-Origin', '*');
headerOptions.append('Content-Type', 'application/json');
let test = {"user": username, "pass": password};
this.credentials = JSON.stringify(test),
console.log("hi "+ this.credentials);
return this.http.post('http://dev.local/scripts/login.php', this.credentials, {
headers: headerOptions
}).pipe(map(
res=>{
console.log(res)
},
err=>
console.log(err)
))
}
}
And here is the button html:
<a id="btn-login" (click)="login()" class="btn btn-success">Login </a>
As you see I am sending a and b as testing values for the functions.
I had the following error:
Http failure during parsing for http://dev.local/scripts/login.php
error : SyntaxError: Unexpected token < in JSON at position 0 at
JSON.parse () at XMLHttpRequest.onLoad
(http://localhost:4200/vendor.js:28274:51) at
ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask
(http://localhost:4200/polyfills.js:2743:31) at Object.onInvokeTask
(http://localhost:4200/vendor.js:56150:33) at
ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask
(http://localhost:4200/polyfills.js:2742:36) at
Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask
(http://localhost:4200/polyfills.js:2510:47) at
ZoneTask.push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask
[as invoke] (http://localhost:4200/polyfills.js:2818:34) at invokeTask
(http://localhost:4200/polyfills.js:3862:14) at
XMLHttpRequest.globalZoneAwareCallback
(http://localhost:4200/polyfills.js:3888:17) message : "Unexpected
token < in JSON at position 0"
And here is a screenshot:
From the network tab, I had an error returned from login.php:
Notice: Undefined index: credentials in
C:\wamp64\www\dev\scripts\login.php on line 8
And if you check my login.php, I already commented this line, so I don't know why is giving me such an error.
Same error was coming when I was trying to send one string message (Like : res.send( "Message from node" )) from node to angular.
I just changed the string into JSON format like {"msg" : "Message from node"}, I was getting the data after this.
I tried after adding this res.setHeader('Content-Type', 'text/plain') it was returning same error in the beginning.
Okay I found the solution:
it seems that I should add the following headers:
headerOptions.append('Access-Control-Allow-Origin', '*');
headerOptions.append('Access-Control-Request-Headers', '*');
headerOptions.append('Content-Type', 'application/json');
headerOptions.append('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,PATCH,OPTIONS');
And from the Apache, we should go to Apache services and check headers_modules.
Then, we should change the httpd.conf, and the following:
<IfModule mod_headers.c>
Header set Access-Control-Allow-Origin: *
</IfModule>

My localhost doesn't use the right path

I'm making a AngularJS app and I'm using a Slim API. I use my API to get data from my DB.
I was testing my app and I noticed something. I have my app in my localhost, but in a server to and they use the exact same code. I use this code to call my API:
angular.module('appDatabaseCtrl', [])
.controller('databaseCtrl', ['$scope','$routeParams', '$http', '$log',
function($scope, $routeParams, $http, $log){
$scope.testDatabaseItems = function(){
$http.get('/api/items').success(function(data) {
$log.info("succes!");
$log.log(data);
})
.error(function (data, status){
$log.error("error!");
$log.log(data);
});
};
$scope.testDatabaseItemById = function(){
$http.get('/api/items/' + $scope.id).success(function(data) {
$log.info("succes!");
$log.log(data);
})
.error(function (data, status){
$log.error("error!");
$log.log(data);
});
};
}
]);
Here is my "index.php" file in my Slim API:
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
//nécessite Slim
require 'vendor/autoload.php';
//Instancie une app de Slim
$app = new \Slim\App;
//Associe type de requête avec fonction et paramêtres
$app->get('/items', 'getItems');
$app->get('/items/{id:\d+}', 'getItemById');
//Démarre l'application
$app->run();
// Accès à la base de données
function DB_Connection() {
$dbhost = "localhost";
$dbuser = "kevdug_angularjs";
$dbpass = "*****************";
$dbname = "angularjs";
$dbh = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $dbh;
}
function getItems() {
$sql = "select * FROM aj_items";
try {
$db = DB_Connection();
$stmt = $db->query($sql);
$list = $stmt->fetchAll(PDO::FETCH_OBJ);
$db = null;
echo json_encode($list);
} catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
function getItemById(Request $request, Response $response, $args) {
$id = $args["id"];
$sql = "select * FROM aj_items WHERE id=".$id;
try {
$db = DB_Connection();
$stmt = $db->query($sql);
$list = $stmt->fetchAll(PDO::FETCH_OBJ);
$db = null;
echo json_encode($list);
} catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
?>
If I use the "testDatabaseItems" function in my app on my server, it perfectly works, but when I try using it in my localhost, I get an 404 error:
"NetworkError: 404 Not Found - http://localhost:8080/api/items"
I know that the reason why I get a 404 error page is simply that the address should be:
localhost:8080/angularjs/api/items
What I want is that in my localhost version, it use the good path but that I don't need to have a different code for my localhost version and my server version.
An other strange thing is that If I go to http://kevdug.webfactional.com/api/items, I get my json object like I expect, but in my localhost, I need to got to "(my localhost address)/api/index.php/items". I need to specify the "index.php" file for some reason and I would like to not need to do that.
Regarding the remote server and local server configuration, just use a simple boolean.
// the uri-base is for both remote and local server the same
$uri = 'http://localhost:8080/';
expecting uri of the current file on remote server to be different than file-uri on local server.
e.g, on remote server it is /www/site/class.php and on local server it is c:/php/class.php if that doesnt work, use another pc-specific fingerprint, or just put a file on the remote-server and check if e.g., file exists.
example code
if(strpos(__FILE__, 'c:/php/') === 0) {
# is local config
$uri .= 'angularjs/api/items';
}
else {
# is remote config
$uri .= 'api/items';
}

My Slim API gives me a 404 error page

I'm making an API for my angular app that will allow me to access my database with Slim. I followed this tutorial http://anjanawijesundara.blogspot.ca/2015/04/crud-application-with-angularjs.html
I have a 'Angularjs' folder. In it, I have my index.html file, my 'api' folder where is this API, my 'app' folder, for the angular app, and a 'assets' folder for the css, img and other js file.
I installed Slim in the 'API' folder with composer (it created a vendor folder) and I have a 'index.php' file next to the vendor folder.
My 'index.php' file (in the api folder) looks like that so far:
<?php
require 'vendor/autoload.php';
$app = new \Slim\App;
$app->get('/Types', 'getTypes');
$app->get('/Types/:id', 'getTypeById');
$app->run();
function DB_Connection() {
$dbhost = "localhost";
$dbuser = "kevdug_portfolio";
$dbpass = "*****************";
$dbname = "portfolio";
$dbh = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $dbh;
}
function getTypes() {
$sql = "select * FROM pt_type";
try {
$db = DB_Connection();
$stmt = $db->query($sql);
$list = $stmt->fetchAll(PDO::FETCH_OBJ);
$db = null;
echo json_encode($list);
} catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
function getTypeById($id) {
$sql = "select * FROM pt_type WHERE id=".$id;
try {
$db = DB_Connection();
$stmt = $db->query($sql);
$list = $stmt->fetchAll(PDO::FETCH_OBJ);
$db = null;
echo json_encode($list);
} catch(PDOException $e) {
echo '{"error":{"text":'. $e->getMessage() .'}}';
}
}
?>
I'm suppose to be able to use my API with this code:
angular.module('appDatabaseCtrl', [])
.controller('databaseCtrl', ['$scope','$routeParams', '$http', '$log',
function($scope, $routeParams, $http, $log){
$scope.testDatabaseTypes = function(){
$http.get('/api/Types').success(function(data) {
$log.info("succes!");
$log.log(data);
})
.error(function (data, status){
$log.error("error!");
$log.log(data);
});
};
$scope.testDatabaseTypesById = function(){
console.log($scope.id);
$http.get('/api/Types/' + $scope.id).success(function(data) {
$log.info("succes!");
$log.log(data);
})
.error(function (data, status){
$log.error("error!");
$log.log(data);
});
};
}
]);
The first function works, but the second returns me a 404 error. You can see what happen yourself with those tree url:
http://kevdug.webfactional.com/#/database
http://kevdug.webfactional.com/api/types
http://kevdug.webfactional.com/api/types/1 <--- can be any id from 1 to 4
It appears that you are using Slim v3 (Judging by $app = new \Slim\App;), however it appears that your route format is that of Slim v2.
$app->get('/Types/:id', 'getTypeById'); should actually be more like $app->get('/Types/{id}', getTypeById);. You can also provide restrictions as to what it accepts like $app->get('/Types/{id:\d+}', getTypeById);
Edit: You are also using an invalid function signature for Slim v3, which is why when navigating to Your Example Url with the literal :id instead of a number it errors. You should use a function signature like
function getTypeById(\Slim\Http\Request $req, \Slim\Http\Response $res, $args) {
$id = $args["id"]; // Rest of your code
}
Finally, i recommend looking up some basic SQL Injection protection tutorials, as because if your current /Types/:id route worked correctly, it would have a SQL Injection Vulnerability. However since that is not the target of this question, i'll just leave a warning.

Http calls to php RestApi take 15sec from angular and only 20ms from postman. What am I missing?

Making requests from angular http to local Apache 2.4 server running php restapi with slim framework. the requests take 15+ seconds to come back. however when I use postman to test the api the responses take 20ms which is what I expect. I'm brand new to php, is there some configuration I'm missing?
<?php
require 'vendor/autoload.php';
$app = new Slim\Slim();
// ==============================
// Connection ===================
// ==============================
function connect()
{
$servername = "localhost";
$username = "root";
$password = "******";
try {
$conn = new PDO("mysql:host=$servername;dbname=contacts", $username, $password);
$conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
//echo "Connected successfully<br>";
} catch (PDOException $e) {
echo "Connection failed: " . $e->getMessage();
}
return $conn;
}
$app->get('/contacts', function () use ($app) {
getContacts(connect(), $app);
});
$app->run();
function getContacts($conn, $app)
{
$app->response()->header("Content-Type", "application/json");
$app->response()->header('Access-Control-Allow-Origin', '*');
$app->response()->header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');
$app->response()->header('Access-Control-Allow-Headers', 'X-Requested-With,content-type');
$app->response()->header('Access-Control-Allow-Credentials', true);
try {
$stmt = $conn->prepare("SELECT * FROM contacts");
$stmt->execute();
echo json_encode($stmt->fetchAll());
} catch (PDOException $e) {
echo $e->getMessage();
}
$conn = null;
}
The Request
$http({
method: 'GET',
url : "http://localhost/Contacts_PHP/contactsAPI.php/contacts"
}).success(function (data) {
$scope.contacts = data;
console.log($scope.contacts);
}).error(function (ex) {
console.log(ex);
});
Try closing the connection by sending the following header:
$app->response->headers->set('Connection', 'close');
But first, set your response body by using the setBody() method, instead of using echo:
$app->response->setBody(json_encode($data));

Categories