check if object exists in Cloud Files (PHP API) - php

I've just started working with the PHP API for Rackspace Cloud Files. So far so good-- but I am using it as sort of a poor man's memcache, storing key/value pairs of serialized data.
My app attempts to grab the existing cached object by its key ('name' in the API language) using something like this:
$obj = $this->container->get_object($key);
The problem is, if the object doesn't exist, the API throws a fatal error rather than simply returning false. The "right" way to do this by the API would probably be to do a
$objs = $this->container->list_objects();
and then check for my $key value in that list. However, this seems way more time/CPU intensive than just returning false from the get_object request.
Is there a way to do a "search for object" or "check if object exists" in Cloud Files?
Thanks

I sent them a pull request and hope it'll get included.
https://github.com/rackspace/php-cloudfiles/pull/35
My pull-request includes an example, for you it would be similar to this:
$object = new CF_Object($this->container, 'key');
if ($object->exists() === false) {
echo "The object '{$object->name}' does not exist.";
}

I have more general way to check if object exists:
try {
$this->_container->get_object($path);
$booExists = true;
} catch (Exception $e) {
$booExists = false;
}

If you dump the $object, you'll see that content_length is zero. Or, last modified will be a zero length string.
Example:
$object = new CF_Object($container, 'thisdocaintthere.pdf');
print_r($object->content_length);
There is also, deep in the dumped parent object, a 404 that will return, but it's private, so you'd need to some hackin' to get at it.
To see this, do the following:
$object = new CF_Object($container, 'thisdocaintthere.pdf');
print_r($object->container->cfs_http);
You'll see inside that object a response_status that is 404
[response_status:CF_Http:private] => 404

I know I'm a little late to the party, but hopefully this will help someone in the future: you can use the objectExists() method to test if an object is available.
public static function getObject($container, $filename, $expirationTime = false)
{
if ($container->objectExists($filename)) {
$object = $container->getPartialObject($filename);
// return a private, temporary url
if ($expirationTime) {
return $object->getTemporaryUrl($expirationTime, 'GET');
}
// return a public url
return $object->getPublicUrl();
}
// object does not exist
return '';
}
Use like...
// public CDN file
$photo = self::getObject($container, 'myPublicfile.jpg');
// private file; temporary link expires after 60 seconds
$photo = self::getObject($container, 'myPrivatefile.jpg', 60);

If you do not want to import opencloud to perform this check you can use the following:
$url = 'YOUR CDN URL';
$code = FALSE;
$options['http'] = array(
'method' => "HEAD",
'ignore_errors' => 1,
'max_redirects' => 0
);
$body = file_get_contents($url, NULL, stream_context_create($options));
sscanf($http_response_header[0], 'HTTP/%*d.%*d %d', $code);
if($code!='200') {
echo 'failed';
} else {
echo 'exists';
}

Related

Part of an array is not accessed through foreach

I am creating a bot for telegram using Botman and I have an issue when trying to get a value from an API response.
This is my class that proccesses the response and returns the message to the user, you can see the API adress.
class TaxiService {
protected $client;
const TAXI_ENDPOINT = 'http://35.204.38.8:4000/api/v1/taxis/%s';
/**
* DogService constructor
*
* #return void
*/
public function __construct(){
$this->client = new Client();
}
public function hireTaxi(){
try {
$lon="Hello";
$endpoint = sprintf(self::TAXI_ENDPOINT, 'Madrid');
$response = json_decode(
$this->client->get($endpoint)->getBody()
);
foreach($response as $key => $value){
foreach($value as $key2 => $value2){
if(is_array($value2)){
foreach($value2 as $key3 => $value3){
$lon = $value3;
}
}
}
}
return $lon;
} catch (Exception $e) {
// If anything goes wrong, we will be sending the user this error message.
return 'An unexpected error occurred. Please try again later.';
}
}
}
This is the response I get when calling the API.
[{"state":"free","name":"Opel","location":
{"lon":1.399,"lat":38.88},"city":"Madrid"},
{"state":"free","name":"Skoda4","location":
{"lon":1.3123,"lat":38.123},"city":"Madrid"},
{"state":"free","name":"Hyundai","location":
{"lon":1.2313,"lat":38.41},"city":"Madrid"}]
When I iterate trough the Array given by ´json_decode´ the ´$long´ variable returns ´Hello´, it doesn't set any value when looping trough the array.
What I want to get is one of the values in the location position of the JSON.
I have tested my function with this site: http://sandbox.onlinephpfunctions.com/ and it gives me a value belonging to the JSON which is what I want but it seems the function is not working in my application.
you need to change:
$response = json_decode(
$this->client->get($endpoint)->getBody()
);
to:
$response = json_decode(
$this->client->get($endpoint)->getBody(), true
);
When TRUE, returned objects will be converted into associative arrays.
You're overwriting the value of $lon on each iteration, which probably isn't what you want. If you just want the lon from the first record that was returned, then you don't need to iterate over everything, just explicitly take the first one:
$response = json_decode(
$this->client->get($endpoint)->getBody()
);
return $response[0]->location->lon;
Or even:
return json_decode($this->client->get($endpoint)->getBody())[0]->location->lon;
neoChiri,
Looks like a scope issue. You would get a $long is not defined error if the variable doesn't exist. So, some variable you created later on in the code is masking the original value.
Hope this helps.

Amazon MWS (PHP) - Report Request API functions return without data, no error thrown

I am currently working with the Amazon MWS to integrate some features into wordpress via a plugin. I am using the client libraries provided by amazon found here:
https://developer.amazonservices.com/api.html?group=bde&section=reports&version=latest
Using these client libraries and the sample php files included I have set up my plugin to make two API calls. The first is requestReport
public function requestInventoryReport() {
AWI_Amazon_Config::defineCredentials(); // Defines data for API Call
$serviceUrl = "https://mws.amazonservices.com";
$config = array (
'ServiceURL' => $serviceUrl,
'ProxyHost' => null,
'ProxyPort' => -1,
'MaxErrorRetry' => 3,
);
$service = new MarketplaceWebService_Client(
AWS_ACCESS_KEY_ID,
AWS_SECRET_ACCESS_KEY,
$config,
APPLICATION_NAME,
APPLICATION_VERSION);
$request = new MarketplaceWebService_Model_RequestReportRequest();
$request->setMerchant(MERCHANT_ID);
$request->setReportType('_GET_MERCHANT_LISTINGS_DATA_');
self::invokeRequestReport($service, $request);
}
private function invokeRequestReport(MarketplaceWebService_Interface $service, $request) {
try {
$response = $service->requestReport($request);
if ($response->isSetRequestReportResult()) {
// Print Out Data
}
} catch (MarketplaceWebService_Exception $ex) {
// Print Out Error
}
}
and the second is getReportRequestList which has code similar to the first function. I am able to run these functions without any errors. The issue that I am having is that $response->isSetRequestReportResult() returns false. From my understanding and looking into the response object, this would suggest that the response object does not have the result. (Upon printing out the response object I can see that the FieldValue of the result array is NULL.) The call, however, does not throw an error but neither does it have the result.
I did some digging through the code and found that the result does actually get returned from the api call but never gets set to the return object when the library attempts to parse it from XML. I've tracked the error down to this block of code (This code is untouched by me and directly from the amazon mws reports library).
private function fromDOMElement(DOMElement $dom)
{
$xpath = new DOMXPath($dom->ownerDocument);
$xpath->registerNamespace('a', 'http://mws.amazonaws.com/doc/2009-01-01/');
foreach ($this->fields as $fieldName => $field) {
$fieldType = $field['FieldType'];
if (is_array($fieldType)) {
if ($this->isComplexType($fieldType[0])) {
// Handle Data
} else {
// Handle Data
}
} else {
if ($this->isComplexType($fieldType)) {
// Handle Data
} else {
$element = $xpath->query("./a:$fieldName/text()", $dom);
$data = null;
if ($element->length == 1) {
switch($this->fields[$fieldName]['FieldType']) {
case 'DateTime':
$data = new DateTime($element->item(0)->data,
new DateTimeZone('UTC'));
break;
case 'bool':
$value = $element->item(0)->data;
$data = $value === 'true' ? true : false;
break;
default:
$data = $element->item(0)->data;
break;
}
$this->fields[$fieldName]['FieldValue'] = $data;
}
}
}
}
}
The data that should go into the RequestReportResult exists at the beginning of this function as a node in the dom element. The flow of logic takes it into the last else statement inside the foreach. The code runs its query and returns $element however $element->length = 13 in my case which causes it to fail the if statement and never set the data to the object. I have also looked into $element->item(0) to see what was in it and it appears to be a dom object itself matching the original dom object but with a bunch of empty strings.
Now, I'm new to working with the MWS and my gut feeling is that I am missing a parameter somewhere in my api call that is messing up how the data is returned and is causing this weird error, but I'm out of ideas at this point. If anyone has any ideas or could point me in the right direction, I would greatly appreciate it.
Thanks for your time!
** Also as a side note, Amazon Scratchpad does return everything properly using the same parameters that I am using in my code **
These works for me, check if you are missing anything.
For RequestReportRequest i am doing this:
$request = new MarketplaceWebService_Model_RequestReportRequest();
$marketplaceIdArray = array("Id" => array($pos_data['marketplace_id']));
$request->setMarketplaceIdList($marketplaceIdArray);
$request->setMerchant($pos_data['merchant_id']);
$request->setReportType($this->report_type);
For GetReportRequestList i am doing this:
$service = new MarketplaceWebService_Client($pos_data['aws_access_key'], $pos_data['aws_secret_access_key'], $pos_data['config'], $pos_data['application_name'], $pos_data['application_version']);
$report_request = new MarketplaceWebService_Model_GetReportRequestListRequest();
$report_request->setMerchant($pos_data["merchant_id"]);
$report_type_request = new MarketplaceWebService_Model_TypeList();
$report_type_request->setType($this->report_type);
$report_request->setReportTypeList($report_type_request);
$report_request_status = $this->invokeGetReportRequestList($service, $report_request, $report_requestID);

How to check on Rackspace if the file is uploaded or not?

I'm working with the Rackspace PHP API, where I've got a requirement to check the file, if it exists then do something and if not then do something.
try {
$file = $container->getObject($end_element);
$fileExists = TRUE;
}
catch(Exception $e) {
$fileExists = FALSE;
}
if ($fileExists) {
// File is their, it needs to be rewrite/overwrite
$file->setContent(fopen('sites/default/files/rackspace/' . $end_element, 'r+'));
$file->update();
// I'm getting this http://docs.rackspace.com/sdks/api/php/class-OpenCloud.ObjectStore.Resource.DataObject.html which I printted print_r($file->update());
}
else {
// New file just to upload
$container->uploadObject($end_element, fopen('sites/default/files/rackspace/' . $end_element, 'r+'), array());
}
To see whether an object exists in a remote container, try using the objectExists method like so:
if ($container->objectExists('objectName.txt')) {
// The object exists
} else {
// The object doesn't exist
}
This will perform a HEAD request on that object, wrapping any 404 failure response in a try/catch block for you.
In terms of finding out the date the object was created, the API only tells you the date of last modification. This will be the create date if you haven't modified the object since it was first uploaded.
To find out the last modified datetime, you need to run:
$object = $container->getObject('objectName.txt');
$created = $object->getLastModified();

How should I properly handle non-cursor pagination with the Facebook PHP SDK?

I am using a few of the Facebook Graph API methods that have pagination successfully using cursor-based pagination, similar to this:
echo '<ul>';
$params = array('limit' => 10);
do {
$groups = (new FacebookRequest(
$session, 'GET', '/me/groups', $params
))->execute()->getGraphObject();
if (null !== $groups->getProperty('paging') && null != $groups->getProperty('paging')->getProperty('next')) {
$params = array('limit' => 10, 'after' => $groups->getProperty('paging')->getProperty('cursors')->getProperty('after'));
} else {
$params = null;
}
foreach ($groups->getProperty('data')->asArray() as $group) {
echo '<li>' . $group->name . '</li>';
}
} while ($params !== null);
echo '</ul>';
This simple code will grab all the groups of the current user. It checks that the paging and paging/next properties are present and if so uses the cursor to setup another iteration of the loop. I realise now this could probably have been done better as the cursor isn't always available. When I use the /{group-id}/feed API endpoint there are the previous and next links but no cursor.
So, how am I supposed to make paginated requests when there is no cursor with the Facebook PHP SDK?
I see other answers suggesting using cURL or even file_get_contents to grab the next and previous URLs but that seems very silly considering I'm using the PHP SDK here - surely there's a built-in way?
I'm using facebook/php-sdk-v4 with Composer - there doesn't seem to be the (old?) $facebook->api(...) functionality availble here either.
Have a look at
https://developers.facebook.com/docs/php/FacebookResponse/4.0.0
There is a method getRequestForNextPage() in the PHP SDK v4.0.0.
// A FacebookResponse is returned from an executed FacebookRequest
try {
$response = (new FacebookRequest($session, 'GET', '/me'))->execute();
// You can get the request back:
$request = $response->getRequest();
// You can get the response as a GraphObject:
$object = $response->getGraphObject();
// You can get the response as a subclass of GraphObject:
$me = $response->getGraphObject(GraphUser::className());
// If this response has multiple pages, you can get a request for the next or previous pages:
$nextPageRequest = $response->getRequestForNextPage();
$previousPageRequest = $response->getRequestForPreviousPage();
} catch (FacebookRequestException $ex) {
echo $ex->getMessage();
} catch (\Exception $ex) {
echo $ex->getMessage();
}
By looking at the source code at
https://github.com/facebook/facebook-php-sdk-v4/blob/4.0-dev/src/Facebook/FacebookResponse.php#L164
it just handles the next property:
return $this->handlePagination('next');
IMHO, using the next property as a default should be fine, opposed to cursors. Furthermore, I don't even see a cursors property when querying a sample group's feed, so this might be obsolete.
References:
https://developers.facebook.com/docs/graph-api/using-graph-api/v2.3#paging

PHP, Check if URL and a file exists ?

I create a plugin for WordPress that requires two files to be exists in order to operate normaly.
The first file is defined as a file system path and the second file is defined as a URL.
Let's say the first file is that:
/home/my_site/public_html/some_folder/required_file.php
and the second file is that:
http://www.my_site.com/some_folder/required_url_file.php
Note that both files are not the same file into the file system. The required_file.php has other content than the required_url_file.php and they act absolutly diferent
Any idea on how to validate the existance of both files ?
You can check both:
$file = '/home/my_site/public_html/some_folder/required_file.php';
$url = 'http://www.my_site.com/some_folder/required_url_file.php';
$fileExists = is_file($file);
$urlExists = is_200($url);
$bothExists = $fileExists && $urlExists;
function is_200($url)
{
$options['http'] = array(
'method' => "HEAD",
'ignore_errors' => 1,
'max_redirects' => 0
);
$body = file_get_contents($url, NULL, stream_context_create($options));
sscanf($http_response_header[0], 'HTTP/%*d.%*d %d', $code);
return $code === 200;
}
Based on Maor H. code sample, here is a function I am using in my plugins:
/**
* Check if an item exists out there in the "ether".
*
* #param string $url - preferably a fully qualified URL
* #return boolean - true if it is out there somewhere
*/
function webItemExists($url) {
if (($url == '') || ($url == null)) { return false; }
$response = wp_remote_head( $url, array( 'timeout' => 5 ) );
$accepted_status_codes = array( 200, 301, 302 );
if ( ! is_wp_error( $response ) && in_array( wp_remote_retrieve_response_code( $response ), $accepted_status_codes ) ) {
return true;
}
return false;
}
I've made this a method in a helper class, however putting this in your theme's functions.php file should make it generally accessible everywhere. However you should always be writing in classes and instantiating them. It is much better for isolating your plugin and theme functionality.
With this in place you can simply use:
if (webItemExists('http://myurl.com/thing.png')) {
print 'it iexists';
}
Most often you will be using WordPress calls to access all items via a relative or fully qualified URL. If you have a relative reference to something such as /uploads/2012/12/myimage.png you can convert those to a fully qualified URL v. a WordPress relative URL by simply adding get_site_url(). $string when calling the webItemExists() function.
As for validating the URL, none of these answers are considering the correct, WordPress way to carry out this task.
For this task wp_remote_head() should be used.
Here's an article I've written about How To Check Whether an External URL Exists with WordPress’ HTTP API. Check it out and figure out how it works.
$file_exists = file_exists($path);
$url_accessable = http_get($url, array("timeout"=>10), $info); // should not be FALSE
$status_code = $info['response_code'] //should be 200
This seems to work for me:
function url_file_exists($url) {
$context = stream_context_create(array('http' =>array('method'=>'HEAD')));
$fd = #fopen($url, 'rb', false, $context);
if ($fd!==false) {
fclose($fd);
return true;
}
return false;
}
If you have PECL http_head function available, you could check if it returns status code 200 for the remote file.
To check if you can access the local file, could use file_exists, but this does not grant that you will be able to access that file. To check if you can read that file, use is_readable.
To check if a file exists, use the file_exists method.
As of PHP 5.0.0, this function can also be used with some URL
wrappers. Refer to Supported Protocols and Wrappers to determine which
wrappers support stat() family of functionality.
if(! (file_exists($url1) && file_exists($url2)) ) {
die("Files don't exist - throw error here.");
}
// Continue as usual - files exist at this point.
remote:
$file = 'http://www.my_site.com/some_folder/required_url_file.php'
if ( #fclose(#fopen($file,"r")) ) echo "File exists!";
local:
$file = '/home/my_site/public_html/some_folder/required_file.php';
if ( is_file($file) ) echo "File exists!";
Use function file_exists()
file_exists('http://www.my_site.com/some_folder/required_url_file.php');
will get you results as True or false.
Checking if a file exists:
if (file_exists('path/to/file.txt')) {
echo "File exists!";
} else {
echo "File doesn't exist.";
}
Checking if a URL is valid:
$data = #file_get_contents("http://url.com/");
if (!$data) {
echo "URL not valid.";
} else {
echo "URL is valid.";
}
Notes:
Ideally you shouldn't try and predict the filesystem. Whilst methods such as file_exists are very helpful, they shouldn't be relied upon and instead you should attempt to write to files, read from them, etc, and then catch and handle any exceptions or errors that occur.

Categories