Hello StackOverflow community
Currently I'm in small project, where a API is required.
I tested some SOAP WSDL and restFul API's, but none worked for me. So I created my own API. As I'm not a professional programer, I want to know if my API is unsafe.
<?php
class API{
public function __construct(){
if($_SERVER['REQUEST_METHOD'] === 'POST'){
if(!empty($_POST)){
$data_array = array();
require_once('PreparePOST.php');
foreach($_POST as $key => $value)
array_push($data_array,array($value => $key));
echo new PreparePOST($data_array);
}else{return new Exception('No Data Requested');}
}else{return new Exception('Request not allowed');}
}
}$init = new API();
?>
Some serious validation and security stuff is done after PreparePOST($data_array);
E.g. only allowed parameters and character escaping.
Notice: This is only the POST implementation the GET implementation and an API Auth Token will be available later.
What are you thinking?
Is this compete nonsense?
Where are possible security issues?
How can I improove my code?
Btw. my project is a Tool, which transmits server infos from our customers (like HD capacity and backup logs) to our server, so we evaluate all server statistically.
Thanks for you advice
KR
As you say that the PreparePOST object does validation and security it would be ideal to share that code too to identify security issues.
One thing which springs to mind right away although not a security issue is that you should throw an Exception rather than return one. Also when you are initializing your API object you don't have any way to catch the exceptions which it may throw. See the try catch block which I've put below.
Also the code isn't super readable, perhaps this would be better:
<?php
class API
{
public function __construct()
{
if($_SERVER['REQUEST_METHOD'] === 'POST')
{
if(!empty($_POST))
{
$data = array();
require_once('PreparePOST.php');
foreach($_POST as $key => $value)
{
array_push($data, array($value => $key));
}
echo new PreparePOST($data);
}
else
{
throw new Exception('No Data Requested');
}
}
else
{
throw new Exception('Request not allowed');
}
}
}
try
{
$init = new API();
}
catch(Exception $e)
{
//handle the exception here
echo $e->getMessage();
}
?>
Specific coding style is down to preference however to keep it readable and maintainable you should definitely make good use of whitespace. There's absolutely nothing gained by keeping code bunched together. In fact quite the opposite.
I wouldn't say there's a need to call your $data variable $data_array. You can see from the code that it's an array, also separate arguments to functions with a comma and a space for readability ,. (When calling array_push).
Related
I have written some functions using Authorize.Net's PHP SDK's that look like the following:
public function getCustomerProfiles() {
$customerProfiles = array();
// Before we can get customer profiles, we need to get a list of all customer id's.
$customerIdListRequest = new AnetAPI\GetCustomerProfileIdsRequest();
$customerIdListRequest->setMerchantAuthentication(self::getMerchantAuth(Config::LOGIN_ID, Config::TRANSACTION_KEY));
$customerIdListController = new AnetController\GetCustomerProfileIdsController($customerIdListRequest);
$customerIdListResponse = $customerIdListController->executeWithApiResponse(\net\authorize\api\constants\ANetEnvironment::SANDBOX);
if(($customerIdListResponse != null) && ($customerIdListResponse->getMessages()->getResultCode() == "Ok")) {
// TODO: Investigate warning about no method named getIds().
foreach( $customerIdListResponse->getIds() as $id ) {
// Now we can get each customer profile.
$request = new AnetAPI\GetCustomerProfileRequest();
$request->setMerchantAuthentication(self::getMerchantAuth(Config::LOGIN_ID, Config::TRANSACTION_KEY));
$request->setCustomerProfileId($id);
$controller = new AnetController\GetCustomerProfileController($request);
$response = $controller->executeWithApiResponse(\net\authorize\api\constants\ANetEnvironment::SANDBOX);
if(($response != null) && ($response->getMessages()->getResultCode() == "Ok")) {
// TODO: Investigate warning about no method named getProfile()
// Add it to the array.
array_push($customerProfiles, $response->getProfile()->xml);
} else {
throw new \Exception($response->getMessages()->getMessage());
}
}
} else {
throw new \Exception($customerIdListResponse->getMessages()->getMessage());
}
return $customerProfiles;
}
Currently, I'm just returning an array of objects. I'd prefer to get the raw XML response. Is this functionality available via Authorize.Net's PHP SDK? Or am I better of using something like Guzzle and making the request manually?
Looking at the source code I think it would be simple enough.
Look the execute method that is invoked by executeWithApiResponse there. See xmlResponse? Just need to store that as a class property (and add a public getter), or maybe tweak the function to take an extra argument telling it to return the raw response. Could hack it, or better yet, extend that ApiOperationBase class (note the interface IApiOperation gives you a outline to follow).
Seeing that serializer also...
$this->apiResponse = $this->serializer->deserialize( $xmlResponse, $this->apiResponseType , 'xml');
Could maybe do something more elegant with that. But not as clear as path I first described.
I have a class that accepts user ID when instantiated. When that ID does not exist in the database, it will throw an exception. Here it is:
class UserModel {
protected $properties = array();
public function __construct($id=null) {
$user = // Database lookup for user with that ID...
if (!$user) {
throw new Exception('User not found.');
}
}
}
My client code looks like this:
try {
$user = new UserModel(123);
} catch (Exception $e) {
$user = new UserModel();
// Assign values to $user->properties and then save...
}
It simply tries to find out if the user exists, otherwise it creates a new one. It works, but I'm not sure if it's proper? If not, please provide a solution.
No this isn't proper, try catch blocks should be used to handle code where anomalous circunstaces could happen. Here you're just checking if the user exists or not so the best way to achieve this is with a simple if else.
from wikipedia definition of programing expception:
"Exception: an abnormal event occurring during the execution of a
routine (that routine is the "recipient" of the exception) during its execution.
Such an abnormal event results from the failure of an operation called by
the routine."
As #VictorEloy and #AIW answered, exceptions are not recommended for flow control.
Complementing, in your case, I would probably stick with a static method for finding existing users that would return an instance of UserModel if it finds, or null in case it does not. This kind of approach is used in some ORM libraries like Active Record from Ruby on Rails and Eloquent from Laravel.
class UserModel {
protected $properties = array();
public static function find($id) {
$user = // Database lookup for user with that ID...
if ($user) {
return new UserModel($user); // ...supposing $user is an array with its properties
} else {
return null;
}
}
public function __construct($properties = array()) {
$this->properties = $properties;
}
}
$user = UserModel::find(5);
if (!$user)
$user = new UserModel();
It is debatable, but I'm going to say this is NOT proper. It has been discussed before. See
Is it "bad" to use try-catch for flow control in .NET?
That seems like a proper behaviour as long as it doesn’t throw when $id is null (that way, you can assume a new one is to be created).
In the case of the code that uses your class, if you’re going to be inserting it with that same ID later, just insert it with that ID to begin with without checking – it could be possible, though unlikely, that something happens between the check and the insertion. (MySQL has ON DUPLICATE KEY UPDATE for that.)
So I am writing an API, and I am fearful that the code I am writing is going to become messy very quickly.
Some pages I need to be fetching data from several different resources from the API, and I am ending up with a whole bunch of try and catch statements everywhere. For example:
$topic_id = 100;
try
{
$topic = AwesomeAPI::get('topics/' . $topic_id);
$parts = AwesomeAPI::get('parts?topic_id=' . $topic_id);
try
{
// Get another resource here
}
catch (Exception $e)
{
// Error
}
}
catch (Exception $e)
{
return Response::error('404');
}
I am confident that this code is quite messy, and it gets even worse if I have to loop through a resource and grab another resource in the loop. Yuck.
I am wondering how to best approach client interactions with an API in a neat fashion.
As I commented before, in my opinion you should have all your API logic inside a class and therefore inside methods. So instead of writing code like the one posted, you can write something like this:
$api = new AwesomeAPI();
$topic = $api->GetTopic($topic_id);
And your AwesomeAPI class could look something like this:
public class AwesomeAPI()
{
public $topic_url = 'somewebsite.com/topics?id{0}';
function GetTopic($topicId)
{
//Some code here
$response = 'Some response (could be a JSON Document)';
return $response;
}
}
This way your code in the application will be more elegant and clear.
Hope this helps you
I'm trying to find some simple examples of a PHP class accessing a distributed API.
Whenever I search for a PHP API client it gives way too much information on building the API itself and little in the way of real access methods beyond the curl examples. A PHP class that includes a good curl method and a way to handle the requests would be nice. I learn by example and lots of re-arranging.
I started with a construct to catch the usual connection settings:
private $hosts = array( URI_1, URI_2, URI_3);
private $users = array( USER_1, USER_2, USER_3);
private $pass = array( PASS_1, PASS_2, PASS_3);
public function __construct($request = array())
{
if (is_array($request)) {
if(isset($request['hostname'])) {
if(in_array($request['hostname'], $hosts)) {
$this->input['hostname'] = $request['hostname'];
}
}
if (isset($request['username'])) {
if(in_array($request['username'], $users)) {
$this->input['username'] = $request['username'];
}
}
if (isset($request['password'])) {
if (in_array($request['password'], $pass)) {
$this->input['password'] = $request['password'];
}
}
if (isset($this->input['hostname']) &&
isset($this->input['username']) &&
isset($this->input['password'])) {
return true;
}
} else {
return false;
}
}
Some simple examples of best practices would make this a lot easier.
Try out Guzzle:
Guzzle takes the pain out of sending HTTP requests and the redundancy
out of creating web service clients.
Guzzle is a framework that includes the tools needed to create a
robust web service client, including: Service descriptions for
defining the inputs and outputs of an API, resource iterators for
traversing paginated resources, batching for sending a large number of
requests as efficiently as possible.
Any advice is welcome!
I have a very limited understanding of php classes but below is my starting point for the route I would like to take. The code is a reflection of what I see in my head and how I would like to go about business. Does my code even look ok, or am I way off base?
What are your thoughts, how would you go about achieving such a task as form->validate->insertquery->sendmail->return messages and errors?
Please try and keep your answers simple enough for me to digest as for me its about understanding whats going on and not just a copy/paste job.
Kindest regards,
Phil.
Note: This is a base structure only, no complete code added.
<?php
//=======================================
//class.logging.php
//========================================
class logging
{
public $data = array();
public $errors = array();
function __construct()
{
array_pop($_POST);
$this->data =($this->_logging)? is_isset(filterStr($_POST) : '';
foreach($this->data as $key=> $value)
{
$this->data[$key] = $value;
}
//print_r($this->data); de-bugging
}
public function is_isset($str)
{
if(isset($str)) ? true: false;
}
public function filterStr($str)
{
return preg_match(do somthing, $str);
}
public function validate_post()
{
try
{
if(!is_numeric($data['cardID'])) ? throw new Exception('CardID must be numeric!') : continue;
}
catch (Exception $e)
{
return $errors = $e->getCode();
}
}
public function showErrors()
{
foreach($errors as $error => $err)
{
print('<div class="notok"></div><br />');
}
}
public function insertQ()
{
$query = "";
}
}
//=======================================
//Usercp.php
//========================================
if(isset($_GET['mode']))
{
$mode = $_GET['mode'];
}
else
{
$mode = 'usercp';
}
switch($mode)
{
case 'usercp':
echo 'Welcome to the User Control Panel';
break;
case 'logging':
require_once 'class.logging.php';
$logger = new logging();
if(isset($_POST['submit'])
{
if($logger->validate_post === true)
{
$logger->insertQ();
require_once '/scripts/PHPMailer/class.phpmailer.php';
$mailer = new PHPMailer();
$mailer->PHPMailer();
}
else
{
echo ''.$logger->showErrors.'';
}
}
else
{
echo
'
<form action="'.$_SERVER['PHP_SELF'].'?mode=logging" method="post">
</form>
';
}
break;
case 'user_logout':
// do somthing
break;
case 'user_settings':
// do somthing
break;
?>
I have decided to use this method for returning errors rather than print them in the method, thanks for the advice Igor!
catch (Exception $e)
{
$this->errors[] = $e->getMessage();
#ERROR DE_BUGGING ONLY================================
#print('<pre>');
#print_r($this->errors);
#print('</pre>');
#=====================================================
}
if($this->errors)
{
return false;
}
else
{
return true;
}
It looks like you have a decent understanding of OOP code. I see declared public vars and even try/catches, though I'd say don't forget the "public" visibility keyword in front of "function __construct()"—not absolutely necessary, but it keeps with good coding practices.
Further, I would say that everything you are doing here has been written, debugged, and fixed, and proven production worthy already by each of the dozens of PHP frameworks out there. The specific task you mentioned, "form->validate->insertquery->sendmail->return messages and errors" is so incredibly easy with Zend Framework, my framework of choice. And I would imagine the same is true for Symphony, Solar, Cake, etc.
Do yourself a favor and stop coding what has been coded already. Learn a framework that has a community, regular updates, and well-written thorough documentation. Again, I recommend Zend Framework.
First advice that comes to mind: Separate logic from presentation. You can start by using some template engine like Smarty. If you will keep it all mixed up, soon it will be a huge dump.
Also try to include class definitions from separate files, and as a next step I would recommend adopting some pattern like Model-View-Controller to separate models from logic.
That's what I can think of without digging too deep into the code.