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';
}
Related
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)
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.
I used Php Slim Framework for my API. I install the Slim Framework to my web root directory on my server and copy the index.php file I coded.
Index.php:
<?php
require 'vendor/autoload.php';
$app = new \Slim\Slim();
$app->contentType('application/json');
$app->get('/users', 'getUsers');
$app->get('/user/:id', 'getUser');
$app->run();
function getConnection() {
$dbhost="localhost";
$dbuser="";
$dbpass="";
$dbname="";
$dbh = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $dbh;
}
function getUsers() {
$sql = "select * FROM manga";
try {
$db = getConnection();
$stmt = $db->query($sql);
$users = $stmt->fetchAll(PDO::FETCH_OBJ);
$db = null;
echo json_encode($users);
}
catch(PDOException $e) {
echo json_encode($e->getMessage());
}
}
?>
I am getting 500 (Internal Server Error).
Edit: I changed "$app = new Slim();" to the "$app = new \Slim\Slim();" then receive the below error.
I am using EasyEngine(Nginx).
Edit-2:Now 500 Internal gone but another error showing.
XMLHttpRequest cannot load http://api.mangayurdu.com/users. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://deneme.mangayurdu.com' is therefore not allowed access.
Here is my code that getting JSON data:
.factory('MY', function($http){
var factory = {};
var url = 'http://api.mangayurdu.com/users?callback=JSON_CALLBACK';
factory.isimler = $http.get(url);
return factory;
})
From the posted code it looks like Slim can't find a function called getUser. getUsers() is defined in your code, but no getUser() function.
try putting this in the start of your PHP page
<?php header('Access-Control-Allow-Origin: *');?>
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));
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.