I found this very interesting project on github: https://github.com/brannondorsey/apibuilder
After starting using it, I noticed that the request limitation won't work properly. The value for the requests in the MySQL database counts to "1000" (or the limit set in $hits_per_day), but the API output is still some data from the database.
The expected error message is simply attached to the API response.
But I would like to have an API that doesn't allow any output and only the error message. Below you can find the concerning file.
public function get_json_from_assoc(&$get_array){
$json_obj = new StdClass();
$pretty_print = $this->pretty_print;
if(!$this->find_config_errors()){
if(isset($get_array['pretty_print'])){
if(strtolower($get_array['pretty_print']) == "true") $pretty_print = true;
if(strtolower($get_array['pretty_print']) == "false") $pretty_print = false;
}
//if API is public or if API is private and a correct private key was provided
if(!$this->private ||
$this->private &&
isset($get_array['private_key']) &&
$this->private_key == $get_array['private_key']){
$query = $this->form_query($get_array);
if($this->check_API_key()
|| !$this->API_key_required){
//if search was included as a parameter in the http request but it isn't allowed in the api's config...
if(isset($get_array['search']) &&
!$this->search_allowed){
$json_obj->error = "search parameter not enabled for this API";
}
else if(isset($get_array['exclude']) &&
!$this->exclude_allowed){
$json_obj->error = "exclude parameter not enabled for this API";
}else{
if($results_array = Database::get_all_results($query)){
if(is_array($results_array)){
// deletes key => value pairs if the value is empty. Only works if array is nested:
// http://stackoverflow.com/questions/5750407/php-array-removing-empty-values
$results_array = array_filter(array_map('array_filter', $results_array));
foreach($results_array as $result_array){
foreach($result_array as $key => $value){
if($key == "COUNT(*)"){
$count = $value;
break;
}
}
}
if(!isset($count)) $json_obj->data = $results_array;
else $json_obj->count = $count;
//COME BACK need to make count only parameter work
}
}else $json_obj->error = "no results found";
}
//only attempt to increment the api hit count if this method is called from a PUBLIC API request
if($this->API_key_required){
$query = "SELECT " . $this->API_hit_date_column_name . " FROM " . Database::$users_table . " WHERE " . $this->API_key_column_name . " = '" . $this->API_key . "' LIMIT 1";
$result = Database::get_all_results($query);
//increments the hit count and/or hit date OR sets the error message if the key has reached its hit limit for the day
if($this->update_API_hits($this->API_key, $result[0][$this->API_hit_date_column_name]) === false){
$json_obj->error = "API hit limit reached";
}
}
}else $json_obj->error = "API key is invalid or was not provided";
//if there was a search and it returned no results
if($this->search != "" &&
!$this->search_has_been_repeated &&
isset($json_obj->error) &&
strstr($json_obj->error, $this->no_results_message) == true){
$this->search_in_boolean_mode = true; //set search in boolean mode to true
$this->search_has_been_repeated = true; //note that the search will now have been repeated
//$this->JSON_string = $this->get_json_from_assoc($get_array, $object_parent_name); //recurse the function (thus re-searching)
return $this->get_json_from_assoc($get_array); //recurse the function (thus re-searching)
}
}else{ //API is private but private_key is invalid or was not provided
$json_obj->error = "this API is private and the private key was invalid or not provided";
}
}else{ //config errors were present
$pretty_print = true; //always output errors in pretty print for readability
$json_obj->config_error = $this->config_errors;
}
return ($pretty_print && version_compare(PHP_VERSION, '5.4.0') >= 0) ? json_encode($json_obj, JSON_PRETTY_PRINT) : json_encode($json_obj);
}
Related
I have a script that loops through 3 files.
Each file posts data to a api and returns a result, either Accepted or Rejected in variable $result.
On a Accepted response the script stops running and echo out the result.
On a Rejected it echo's out the rejected response and carries on to the next file.
The problem is : Lets say all 3 files give a Rejected reponse , it echo's out 3 rejected responses.
How can i only echo out a single generic response if it does not get a Accepted Response.
foreach($getSeq as $key){
$fileName = $key->file;
include_once 'Lenders/' . $fileName;
if($result == 'Accepted'){
echo 'Accepted';
break;
}
if($result == 'Rejected'){
echo 'Rejected';
}
}
you can do it with array() like below:
<?php
$resultArr = array(); // suppose we insert below Accepted = 1 and Rejected = 0
foreach($getSeq as $key){
$fileName = $key->file;
include_once 'Lenders/' . $fileName;
if($result == 'Accepted'){
echo "Accepted";
$resultArr[] = 1;
break;
}
if($result == 'Rejected'){
$resultArr[] = 0;
}
}
if(!in_array(1, $resultArr)){
echo 'Rejected';
}
Try this, this is specifically for 3 reject response
$failed = 0;
foreach($getSeq as $key){
$fileName = $key->file;
include_once 'Lenders/' . $fileName;
if($result == 'Accepted'){
echo 'Accepted';
break;
}
if($result == 'Rejected'){
$failed++;
}
}
if($failed == 3) {
echo "Rejected";
}
You didn't said if what will happens to other ratio (1A:2R, 2A:1R), so I just created it for 3 rejects
This is a sample of individual functions that validate form data from a request submission. A variable of true has been set and each function checks for validation requirements then either continues without returning anything or returns false and changes the $check value. The function down the bottom then checks if the $check value has changed to false and if it has the SQL statement will not be run.
$check = true;
function productNameValidation(){
if(isset($_REQUEST['product_name']) && !empty($_REQUEST['product_name']) && preg_match("/^[A-Za-z0-9 :]*[A-Za-z0-9][A-Za-z0-9 :]{0,50}$/",($_REQUEST['product_name']))){
//then $valid['ID'] = "string: " . $_REQUEST['ID']
$valid['product_name'] = $_REQUEST['product_name'];
$err['product_name'] = "No errors";
//if not
} else {
if(empty($_REQUEST['product_name'])){
$valid['product_name'] = "No data entered!";
} else {
$valid['product_name'] = $_REQUEST['product_name'];
} //$err['ID'] = "error message"
$err['product_name'] = "Product Name must only contain letters, numbers and ':'!";
$check = false;
}
}
function checkProduct()
{
productNameValidation();
productGenreValidation();
productPriceValidation();
productEsrbValidation();
productThumbnailValidation();
releaseDateValidation();
return $check;
}
if($check == true)
{
//Insert into database
}
What you need to do is add different variables on different functions. If you are working this code to the method that it begins as true and is required to be checked and if the check fails then becomes false, try this method:
// $check = true;
function productNameValidation(){
$nameValidation = TRUE;
if(isset($_REQUEST['product_name']) && !empty($_REQUEST['product_name']) && preg_match("/^[A-Za-z0-9 :]*[A-Za-z0-9][A-Za-z0-9 :]{0,50}$/",($_REQUEST['product_name']))){
//then $valid['ID'] = "string: " . $_REQUEST['ID']
$valid['product_name'] = $_REQUEST['product_name'];
$err['product_name'] = "No errors";
//if not
} else {
if(empty($_REQUEST['product_name'])){
$valid['product_name'] = "No data entered!";
} else {
$valid['product_name'] = $_REQUEST['product_name'];
} //$err['ID'] = "error message"
$err['product_name'] = "Product Name must only contain letters, numbers and ':'!";
$nameValidation = false;
}
return $nameValidation;
}
function checkProduct()
{
$checkProduct = true; ///true until proven false.
$checkProduct = productNameValidation();
//This code gives $checkProduct the boolean value returned
//from the function
$checkProduct = productGenreValidation();
$checkProduct = productPriceValidation();
$checkProduct = productEsrbValidation();
$checkProduct = productThumbnailValidation();
$checkProduct = releaseDateValidation();
return $checkProduct;
}
if($checkProduct == true)
{
//Insert into database
}
What I have done here is each function returns a TRue/False flag boolean variables which can be checked with an if(){ statement, you can run through numerous functions in this way checking each aspect you need. The important point is that you need to return a value from each function and you can set the booleans manually with initial settings which is then updated upon conditionals - such as setting $checkProduct = TRUE until it is FALSE from any sub function.
Global variables are really not a good idea in this case.
Edit: Thanks to #Edward for some clarification of boolean return code.
You can do something like that:
function productNameValidation(){
$check = true;
if(isset($_REQUEST['product_name']) && !empty($_REQUEST['product_name']) && preg_match("/^[A-Za-z0-9 :]*[A-Za-z0-9][A-Za-z0-9 :]{0,50}$/",($_REQUEST['product_name']))){
//then $valid['ID'] = "string: " . $_REQUEST['ID']
$valid['product_name'] = $_REQUEST['product_name'];
$err['product_name'] = "No errors";
//if not
} else {
if(empty($_REQUEST['product_name'])){
$valid['product_name'] = "No data entered!";
} else {
$valid['product_name'] = $_REQUEST['product_name'];
} //$err['ID'] = "error message"
$err['product_name'] = "Product Name must only contain letters, numbers and ':'!";
$check = false;
}
return $check;
}
if(productNameValidation()) {
....
}
You can return $check in your validation functions which will allow you to use the value of $check outside the function scope like this: $check = productNameValidation(). Another important note which I saw mentioned above: You should try to avoid the global scope as much as possible.
You can use check like a local variable not global, so in function.
Instead if you want it as a global, at the beginning of the function, you have to specify that you referring to
global $check;
$_GET['numberofwelds']; & $_GET['numberofconwelds']; are sent to this script using GET JSON. I want to add these together, and then use json_encode to send a total back to the callback (in another php script) . If both $_GET 's are empty, then I want nothing to happen. How should I change this?
$numberofwelds = $_GET['numberofwelds'];
$numberofconwelds = $_GET['numberofconwelds'];
if (isset($_GET['numberofwelds']) && $_GET['numberofwelds'] != '' {
$numberofwelds + $numberofconwelds = $sum_total;
echo json_encode($sumtotal);
} else {
exit()
}
Firstly, you are trying to access your $_GET variables without checking they exist first.
Secondly, you should be throwing Exceptions instead of just calling exit() or die(). You can then log them with $e->getMessage() or write them to the local filesystem.
Finally, you need to validate your data. Make sure it is what you expect it to be.
if (isset($_GET['numberofwelds']) && isset($_GET['numberofconwelds']))
{
// Now we know both values definitely exist, VALIDATE them
$numwelds = $_GET['numberofwelds'];
$numconwelds = $_GET['numberofconwelds'];
if (is_int($numwelds) && is_int($numconwelds))
{
// Calculate your total
$total = $numwelds + $numconwelds;
echo json_encode($total);
}
else
{
// We get here because your GET variables do exist but they aren't
// numbers as you expect (you or someone else has sent rubbish data)
// You want to do nothing, although I would return an error in your json
// to be displayed to the user or logged by the consumer of the service
}
}
else
{
// We get here because your GET variables simply don't exist. They haven't been
// passed in as you are expecting them to be
// You want to do nothing, although I would return an error in your json
// to be displayed to the user or logged by the consumer of the service
}
Always code defensively.
I'm going to show you what I would do in this situation.
if (isset($_GET['numberofwelds']) && isset($_GET['numberofconwelds']))
{
$numwelds = $_GET['numberofwelds'];
$numconwelds = $_GET['numberofconwelds'];
if (is_int($numwelds) && is_int($numconwelds))
{
$total = $numwelds + $numconwelds;
$response = array("status" => "success", "message" => $total);
echo $response;
}
else
{
$response = array("status" => "failure", "message" => "GET params were not numbers");
echo $response;
}
}
else
{
$response = array("status" => "failure", "message" => "GET params do not exist");
echo $response;
}
Then, in your consuming service (most likely a JavaScript / jQuery AJAX call), you can do the following:
.done(function(data) {
var json = $.parseJSON(data);
if (data.status === "success") {
// Yay, we got a success back
console.log("The total is: " + data.message);
} else if (data.status === "failure") {
// Uh oh, something's gone wrong server-side
console.log(data.message);
}
});
change this
if ($_GET['numberofwelds'] != '' && $_GET['numberofconwelds'] != '') {
$numberofwelds + $numberofconwelds = $sum_total;
echo json_encode($sumtotal);
} else {
exit()
}
to this
if ($numberofwelds && $numberofconwelds ) {
$sum_total = array(
'sumTotal' => $numberofwelds + $numberofconwelds,
);
echo json_encode($sum_total);
}else {
exit();
}
Please always check existence of the array keys with isset() construction or array_key_exists() function.
if (isset($_GET['numberofwelds']) && $_GET['numberofwelds'] != '' && isset($_GET['numberofconwelds']) && $_GET['numberofconwelds'] != '') {
echo json_encode(array("total" => $_GET['numberofwelds'] + $_GET['numberofconwelds']));
} else {
exit();
}
UPDATE
With is_numeric() function this code should be more robust:
if (isset($_GET['numberofwelds']) && is_numeric($_GET['numberofwelds']) && isset($_GET['numberofconwelds']) && is_numeric($_GET['numberofconwelds'])) {
echo json_encode(array("total" => $_GET['numberofwelds'] + $_GET['numberofconwelds']));
} else {
exit();
}
PHP reference: array_key_exists()
PHP reference: isset()
$numberofwelds = json_decode($_GET['numberofwelds'], true);
$numberofconwelds = json_decode($_GET['numberofconwelds'], true);
$mergedJson = array_merge(numberofwelds, numberofconwelds);
echo json_encode($mergedJson);
This should do it. It grabs the json, decodes and turns it in to an array (second parameter of json_decode set to true) and then combines them.
I am trying to GET different rows from different columns in php/mysql, and pack them into an array. I am able to successfully GET a jason encoded array back IF all values in the GET string match. However, if there is no match, the code echos 'no match', and without the array. I know this is because of the way my code is formatted. What I would like help figuring out, is how to format my code so that it just displays "null" in the array for the match it couldn't find.
Here is my code:
include '../db/dbcon.php';
$res = $mysqli->query($q1) or trigger_error($mysqli->error."[$q1]");
if ($res) {
if($res->num_rows === 0)
{
echo json_encode($fbaddra);
}
else
{
while($row = $res->fetch_array(MYSQLI_BOTH)) {
if($_GET['a'] == "fbaddra") {
if ($row['facebook'] === $_GET['facebook']) {
$fbaddr = $row['addr'];
} else {
$fbaddr = null;
}
if ($row['facebookp'] === $_GET['facebookp']) {
$fbpaddr = $row['addr'];
} else {
$fbpaddr = null;
}
$fbaddra = (array('facebook' => $fbaddr, 'facebookp' => $fbpaddr));
echo json_encode($fbaddra);
}
}
}
$mysqli->close();
UPDATE: The GET Request
I would like the GET request below to return the full array, with whatever value that didn't match as 'null' inside the array.
domain.com/api/core/engine.php?a=fbaddra&facebook=username&facebookp=pagename
The GET above currently returns null.
Requests that work:
domain.com/api/core/engine.php?a=fbaddra&facebook=username or domain.com/api/core/engine.php?a=fbaddra&facebookp=pagename
These requests return the full array with the values that match, or null for the values that don't.
TL;DR
I need assistance figuring out how to format code to give back the full array with a value of 'null' for no match found in a row.
rather than assigning as 'null' assign null. Your full code as follows :
include '../db/dbcon.php';
$res = $mysqli->query($q1) or trigger_error($mysqli->error."[$q1]");
if ($res) {
if($res->num_rows === 0)
{
echo json_encode('no match');
}
else
{
while($row = $res->fetch_array(MYSQLI_BOTH)) {
if($_GET['a'] == "fbaddra") {
if ($row['facebook'] === $_GET['facebook']) {
$fbaddr = $row['dogeaddr'];
//echo json_encode($row['dogeaddr']);
} else {
$fpaddr = null;
}
if ($row['facebookp'] === $_GET['facebookp']) {
$fbpaddr = $row['dogeaddr'];
//echo json_encode($row['dogeaddr']);
} else {
$fbpaddr = null;
}
$fbaddra = (array('facebook' => $fbaddr, 'facebookp' => $fbpaddr));
echo json_encode($fbaddra);
}
}
}
$mysqli->close();
You can even leave else part altogether.
Check your code in this fragment you not use same names for variables:
if ($row['facebook'] === $_GET['facebook']) {
$fbaddr = $row['dogeaddr'];
//echo json_encode($row['dogeaddr']);
} else {
$fpaddr = 'null';
}
$fbaddr not is same as $fpaddr, this assign wrong result to if statement.
It was the mysql query that was the problem.
For those who come across this, and need something similar, you'll need to format your query like this:
** MYSQL QUERY **
if ($_GET['PUTVALUEHERE']) {
$g = $_GET['PUTVALUEHERE'];
$gq = $mysqli->real_escape_string($g);
$q1 = "SELECT * FROM `addrbook` WHERE `facebookp` = '".$gq."' OR `facebook` = '".$gq."'";
}
** PHP CODE **
if($_GET['PUTVALUEHERE']{
echo json_encode($row['addr']);
}
I am working with SilverStripe, and I am working on making a newspage.
I use the DataObjectAsPage Module( http://www.ssbits.com/tutorials/2012/dataobject-as-pages-the-module/ ), I got it working when I use the admin to publish newsitems.
Now I want to use the DataObjectManager Module instead of the admin module to manage my news items. But this is where the problem exists. Everything works fine in draft mode, I can make a new newsitem and it shows up in draft. But when I want to publish a newsitem, it won't show up in the live or published mode.
I'm using the following tables:
-Dataobjectaspage table,
-Dataobjectaspage_live table,
-NewsArticle table,
-NewsArticle_Live table
The Articles have been inserted while publishing in the Dataobjectaspage table and in the NewsArticle table... But not in the _Live tables...
Seems the doPublish() function hasn't been used while 'Publishing'.
So I'm trying the use the following:
function onAfterWrite() {
parent::onAfterWrite();
DataObjectAsPage::doPublish();
}
But when I use this, it gets an error:
here is this picture
It seems to be in a loop....
I've got the NewsArticle.php file where I use this function:
function onAfterWrite() {
parent::onAfterWrite();
DataObjectAsPage::doPublish();
}
This function calls the DataObjectAsPage.php file and uses this code:
function doPublish() {
if (!$this->canPublish()) return false;
$original = Versioned::get_one_by_stage("DataObjectAsPage", "Live", "\"DataObjectAsPage\".\"ID\" = $this->ID");
if(!$original) $original = new DataObjectAsPage();
// Handle activities undertaken by decorators
$this->invokeWithExtensions('onBeforePublish', $original);
$this->Status = "Published";
//$this->PublishedByID = Member::currentUser()->ID;
$this->write();
$this->publish("Stage", "Live");
// Handle activities undertaken by decorators
$this->invokeWithExtensions('onAfterPublish', $original);
return true;
}
And then it goes to DataObject.php file and uses the write function ():
public function write($showDebug = false, $forceInsert = false, $forceWrite = false, $writeComponents = false) {
$firstWrite = false;
$this->brokenOnWrite = true;
$isNewRecord = false;
if(self::get_validation_enabled()) {
$valid = $this->validate();
if(!$valid->valid()) {
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
throw new ValidationException($valid, "Validation error writing a $this->class object: " . $valid->message() . ". Object not written.", E_USER_WARNING);
return false;
}
}
$this->onBeforeWrite();
if($this->brokenOnWrite) {
user_error("$this->class has a broken onBeforeWrite() function. Make sure that you call parent::onBeforeWrite().", E_USER_ERROR);
}
// New record = everything has changed
if(($this->ID && is_numeric($this->ID)) && !$forceInsert) {
$dbCommand = 'update';
// Update the changed array with references to changed obj-fields
foreach($this->record as $k => $v) {
if(is_object($v) && method_exists($v, 'isChanged') && $v->isChanged()) {
$this->changed[$k] = true;
}
}
} else{
$dbCommand = 'insert';
$this->changed = array();
foreach($this->record as $k => $v) {
$this->changed[$k] = 2;
}
$firstWrite = true;
}
// No changes made
if($this->changed) {
foreach($this->getClassAncestry() as $ancestor) {
if(self::has_own_table($ancestor))
$ancestry[] = $ancestor;
}
// Look for some changes to make
if(!$forceInsert) unset($this->changed['ID']);
$hasChanges = false;
foreach($this->changed as $fieldName => $changed) {
if($changed) {
$hasChanges = true;
break;
}
}
if($hasChanges || $forceWrite || !$this->record['ID']) {
// New records have their insert into the base data table done first, so that they can pass the
// generated primary key on to the rest of the manipulation
$baseTable = $ancestry[0];
if((!isset($this->record['ID']) || !$this->record['ID']) && isset($ancestry[0])) {
DB::query("INSERT INTO \"{$baseTable}\" (\"Created\") VALUES (" . DB::getConn()->now() . ")");
$this->record['ID'] = DB::getGeneratedID($baseTable);
$this->changed['ID'] = 2;
$isNewRecord = true;
}
// Divvy up field saving into a number of database manipulations
$manipulation = array();
if(isset($ancestry) && is_array($ancestry)) {
foreach($ancestry as $idx => $class) {
$classSingleton = singleton($class);
foreach($this->record as $fieldName => $fieldValue) {
if(isset($this->changed[$fieldName]) && $this->changed[$fieldName] && $fieldType = $classSingleton->hasOwnTableDatabaseField($fieldName)) {
$fieldObj = $this->dbObject($fieldName);
if(!isset($manipulation[$class])) $manipulation[$class] = array();
// if database column doesn't correlate to a DBField instance...
if(!$fieldObj) {
$fieldObj = DBField::create('Varchar', $this->record[$fieldName], $fieldName);
}
// Both CompositeDBFields and regular fields need to be repopulated
$fieldObj->setValue($this->record[$fieldName], $this->record);
if($class != $baseTable || $fieldName!='ID')
$fieldObj->writeToManipulation($manipulation[$class]);
}
}
// Add the class name to the base object
if($idx == 0) {
$manipulation[$class]['fields']["LastEdited"] = "'".SS_Datetime::now()->Rfc2822()."'";
if($dbCommand == 'insert') {
$manipulation[$class]['fields']["Created"] = "'".SS_Datetime::now()->Rfc2822()."'";
//echo "<li>$this->class - " .get_class($this);
$manipulation[$class]['fields']["ClassName"] = "'$this->class'";
}
}
// In cases where there are no fields, this 'stub' will get picked up on
if(self::has_own_table($class)) {
$manipulation[$class]['command'] = $dbCommand;
$manipulation[$class]['id'] = $this->record['ID'];
} else {
unset($manipulation[$class]);
}
}
}
$this->extend('augmentWrite', $manipulation);
// New records have their insert into the base data table done first, so that they can pass the
// generated ID on to the rest of the manipulation
if(isset($isNewRecord) && $isNewRecord && isset($manipulation[$baseTable])) {
$manipulation[$baseTable]['command'] = 'update';
}
DB::manipulate($manipulation);
if(isset($isNewRecord) && $isNewRecord) {
DataObjectLog::addedObject($this);
} else {
DataObjectLog::changedObject($this);
}
$this->onAfterWrite();
$this->changed = null;
} elseif ( $showDebug ) {
echo "<b>Debug:</b> no changes for DataObject<br />";
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
}
// Clears the cache for this object so get_one returns the correct object.
$this->flushCache();
if(!isset($this->record['Created'])) {
$this->record['Created'] = SS_Datetime::now()->Rfc2822();
}
$this->record['LastEdited'] = SS_Datetime::now()->Rfc2822();
} else {
// Used by DODs to clean up after themselves, eg, Versioned
$this->extend('onAfterSkippedWrite');
}
// Write ComponentSets as necessary
if($writeComponents) {
$this->writeComponents(true);
}
return $this->record['ID'];
}
Look at the $this->onAfterWrite();
It probably goes to my own function on NewsArticle.php and there starts the loop! I'm not sure though, so i could need some help!!
Does anyone knows how to use the doPublish() function?
The reason that is happening is that in the DataObjectAsPage::publish() method, it is calling ->write() - line 11 of your 3rd code sample.
So what happens is it calls ->write(), at the end of ->write() your onAfterWrite() method is called, which calls publish(), which calls write() again.
If you remove the onAfterWrite() function that you've added, it should work as expected.
The doPublish() method on DataObjectAsPage will take care of publishing from Stage to Live for you.