PHP - Rackspace CloudFiles API check if the file path already exists? - php

I'm working with the Rackspace CloudFiles API, where I've got a requirement to check for folder exists inside a container.
I have searched across different areas I could find solution to find if container exists or the object exists.
For example:
Format: container/folder/subfolder/file
Actual file stored location:
test/test_folder/test_subfolder/test.txt
I want to know is my container has already got a folder called test_folder
And I came across something which says path, but am not sure we have this method exists!
getObjects ->> 'path', 'file path to search'

I can't really answer this question in the context of PHP or Guzzle, but I can provide some info on Cloud Files and some command line curl examples that might help.
Rackspace Cloud Files does not really have the concept of "folders" inside containers. You have a URL with the following pieces:
https://{storage_endpoint}/{account_name}/{container_name}/{object_name}
You can however emulate folders by creating objects with the "/" character in the name. Then when performing a container listing, you can set the "prefix" and "delimiter" query string parameters to emulate a folder-like behavior.
For example, say you do a listing of your container to see all your objects:
$ curl -i -XGET -H"x-auth-token: $AUTH_TOKEN" https://storage101.iad3.clouddrive.com/v1/$ACCOUNT_NAME/$CONTAINER_NAME
HTTP/1.1 200 OK
...
Date: Thu, 01 Dec 2016 02:16:53 GMT
foo/file1.txt
foo/bar/file2.txt
baz/file3.txt
baz/file4.txt
Here we have four objects named "foo/file1.txt", "foo/bar/file2.txt", "baz/file3.txt" and "baz/file4.txt".
The easiest way to test for the existence of the folder "foo" would be to set the prefix to "foo/" and the delimiter to "/" as follows:
$ curl -i -XGET -H"x-auth-token: $AUTH_TOKEN" https://storage101.iad3.clouddrive.com/v1/$ACCOUNT_NAME/$CONTAINER_NAME?prefix=foo/&delimiter=/
HTTP/1.1 200 OK
...
Date: Thu, 01 Dec 2016 02:16:45 GMT
foo/file1.txt
foo/bar/file2.txt
As you can see, if any objects exist with that prefix, then a HTTP 200 is returned along with a listing of the objects that matched the prefix. If no objects exist with that prefix, the "folder" does not exist and a HTTP 204 will be returned.
If you now want to test for a "sub-folder" inside "foo", you can just perform another container listing changing the prefix to "foo/bar/" and keeping the delimiter of "/".
Further, if you want to create a folder "images" and have it contain "cat.jpg", you don't need to create a folder first, you just create an object called "images/cat.jpg" that contains the data for cat.jpg.
You can find more information about Rackspace Cloud Files and Pseudo-Hierarchical folders here:
https://developer.rackspace.com/docs/cloud-files/v1/general-api-info/pseudo-hierarchical-folders-and-directories/

Even though #hurricanerix answer helped me, I want to post exact PHP method and snippet to help other is future.
$client = new Rackspace(Rackspace::US_IDENTITY_ENDPOINT, array(
'username' => 'XXXXXXXX',
'apiKey' => 'XXXXXXXXXXXXXXXXXXX'
));
$total = 0;
$containerObjects = array();
$objectStoreService = $client->objectStoreService(null, 'XX');
$container = $objectStoreService->getContainer('test');
$objData = $container->ObjectList(array('prefix'=>"test_folder/", 'delimiter'=>"/"));
if(is_object($objData))
{
$total = $objData->count();
if ($total == 0)
break;
foreach ($objData as $object) {
$containerObjects[] = $object->getName();
}
}
var_dump($containerObjects);
Output
array (size=1)
0 => string 'test/test_folder/test_subfolder/' (length=32)
Hope this will help.

Related

Can't see created folder in teamdrive root

I'm creating a folder inside teamdrive root with google-drive-sdk and it works but with some delay after API call finished. If I try to query root folder with the name of newly created folder right after creation - I get an empty array. But if I do the same after couple of seconds I see the new item.
$file = $service->files->create(
$folder,
[
"supportsTeamDrives" => true
]
);
printf("Folder ID: %s\n", $file->id);
I see the folder ID
$params = [
"q" => "'{$teamDriveId}' in parents and trashed = false and mimeType = 'application/vnd.google-apps.folder' and name ='$path'",
"pageSize" => 1,
"corpora" => "teamDrive",
"includeTeamDriveItems" => true,
"supportsTeamDrives" => true,
"teamDriveId" => $teamDriveId
];
$files = $service->files->listFiles($params);
$list = $files->getFiles();
var_dump($list);
Empty array
But if I do 'sleep(3)' before query - an array is not empty and contains new folder.
I didn't find any information about this delay in documentation. What is it and is there a way to get the result without delays?
While I can't speak to the internals of the Drive API, I can imagine that any delay between creating the folder, and the folder being queryable from Files.list(), is due to internal indexing and data propagation for Team Drives, since they are different than the regular Drive files.
Note that such an use case -- I create this file then immediately need to find it -- is avoidable - the act of creating the file has a return value that includes the direct handle to the file created.
Response
If successful, this method returns a Files resource in the response body.

Rackspace - php-opencloud filters - Documentation for valid ObjectList filters?

Anyone know if/where there is documentation for valid ObjectList filter arrays?
The project's entry on github has a tiny blurb on it directing me to the API documentation, but that also fails to have a comprehensive list, and a search on 'filters' talks about containers only, not the object themselves.
I have a list of videos, each in four different formats named the same thing (sans filetype). Using the php-opencloud API, I want to GET only one of those video formats (to grab the unique filename rather than all its different formats).
I figured using a filter is the way to go, but I can't find any solid documentation.
Someone has got to have done this before. Help a noob out?
Most of the links on this page are dead now. Here's a current link to the php-opencloud documentation, which includes an example of using a prefix to filter the objectList results:
http://docs.php-opencloud.com/en/latest/services/object-store/objects.html#list-objects-in-a-container
I didn't find documentation of this, but apparently when the Rackspace Cloud Files documentation mentions arguments in a query string, those translate to arguments in an objectList method call like this:
GET /v1/MossoCloudFS_0672d7fa-9f85-4a81-a3ab-adb66a880123/AppleType?limit=2&marker=grannysmith
equals
$container->objectList(array('limit'=>'2', 'marker'=>'grannysmith'));
As Glen's pointed out, there isn't support (at the moment) for the service to apply filters on objects. The only thing which you might be interested in is supplying a prefix, which allows you to refine the objects returned based on how the filenames start. So if you sent 'bobcatscuddling' as the prefix, you'd get back all associated video formats for that one recording.
Your only option, it seems, is to get back all objects and iterate over the collection:
use OpenCloud\Rackspace;
$connection = new Rackspace(RACKSPACE_US, array(
'username' => 'foo',
'apiKey' => 'bar'
));
$service = $connection->objectStore('cloudFiles', 'DFW', 'publicURL');
$container = $service->container('CONTAINER_NAME');
$processedObjects = array();
$marker = '';
while ($marker !== null) {
$objects = $container->objectList('marker' => $marker);
$total = $objects->count();
$count = 0;
while ($object = $objects->next()) {
// Extract the filename
$filename = pathinfo($object->name, PATHINFO_FILENAME);
// Make sure you only deal with the filename once (i.e. to ignore different extensions)
if (!in_array($processedObjects, $filename)) {
// You can do your DB check here...
// Stock the array
$processedObjects[] = $filename;
}
$count++;
$marker = ($count == $total) ? $object->name : null;
}
}
What you'll notice is that you're incrementing the marker and making a new request for each 10,000 objects. I haven't tested this, but it'll probably lead you in the right direction.
Unfortunately, the underlying API doesn't support filtering for objects in Swift/Cloud Files containers (cf. http://docs.rackspace.com/files/api/v1/cf-devguide/content/List_Objects-d1e1284.html). The $filter parameter is supported as part of the shared code, but it doesn't actually do anything with Cloud Files here.
I'll see if I can get the docs updated to reflect that.

Get Cname records with NetDNS or get_dns_record

I'm trying get a list of CNAME records using PHP.
This method used to work when I was hosting the code on my old Windows 7 machine, but I moved it to an Ubuntu machine (similar AMP stack setup), and it no longer returned CNAME records for the $url. I uploaded the code to a Windows server and still yet, no CNAME records.
$records['cname'] = dns_get_record($url, DNS_CNAME);
Not that I'm claiming the OS has much to do with anything, maybe I had something set up a certain way on my old machine that allowed this to work. It currently returns a simple empty array, where as it used to return a list of CNAME records that matched up with what was in my DNS management service. I've read the article here:
Why wouldn't dns_get_record show CNAMEs when I KNOW they exist?
and ended up trying to implement the functionality with Pear's NetDns2 Library, with the following code. And still, the answer array of the response is empty. Not sure if the problem is the same from get_dns_record to NetDNS2 or if I'm doing something wrong in both cases, but the sites tested surely have CNAME records, including google.com and yahoo.com.
//using Google Name Server
$rslvr = new Net_DNS2_Resolver(array('nameservers' => array('8.8.8.8')));
$records['cname'] = $rslvr->query($url, 'CNAME');
Any help is appreciated, the end goal is to be able to obtain a list of CNAME records like I was on my old machine.
Works here with PHP 5.4.9.
The first record (cweiske.de) is no CNAME but directly points to an IP address:
php > var_dump(dns_get_record('cweiske.de', DNS_CNAME));
array(0) {
}
The second is actually a CNAME to the first record:
php > var_dump(dns_get_record('www.cweiske.de', DNS_CNAME));
array(1) {
[0] =>
array(5) {
'host' =>
string(14) "www.cweiske.de"
'class' =>
string(2) "IN"
'ttl' =>
int(86400)
'type' =>
string(5) "CNAME"
'target' =>
string(10) "cweiske.de"
}
}
dig shows the same:
$ dig cweiske.de
cweiske.de. 577 IN A 83.169.7.198
$ dig www.cweiske.de
www.cweiske.de. 86397 IN CNAME cweiske.de.
cweiske.de. 597 IN A 83.169.7.198
To check if it's your or PHP's problem, use dig or nslookup to test.

Portably retrieve Subversion 1.7 revision in PHP?

In Subversion 1.6, there was an .svn directory in every working copy directory. I could use the following code to quickly retrive the current revision number without the need for shell access/execution.
public function getSubversionRevision() {
if(file_exists("../.svn/entries")) {
$svn = File("../.svn/entries");
return (int)$svn[3];
}
return false;
}
Subversion 1.7 breaks this code. There is now only one .svn directory per local repository. There is an entries file in this directory but it no longer has anything useful for me. It looks like everything I need is now in a SQLite database. Specifically wc.db. I suppose I could use PHP's SQLite functions to get the info I need, but this sounds a little too expensive to run on every (or close to every) page load.
Any ideas? Breaking out the exec function and hoping that Subversion binaries are installed (and in the $PATH!) is a last resort. To summarize, I need to find a way to locate the .svn directory at the root of the repository (which could be different depending on your checkout location) and then somehow parse a file in there (probably wc.db) in a cost-effective way.
try using a SVN library SVN as it will give you access to repository information and more functionality over SVN repository.
Take a look at function svn_status you will receive and array of svn repository information
Array (
[0] => Array (
[path] => /home/bob/wc/sandwich.txt
[text_status] => 8 // item was modified
[repos_text_status] => 1 // no information available, use update
[prop_status] => 3 // no changes
[repos_prop_status] => 1 // no information available, use update
[name] => sandwich.txt
[url] => http://www.example.com/svnroot/deli/trunk/sandwich.txt
[repos] => http://www.example.com/svnroot/
[revision] => 123 // <-- Current Revision
//..
)
)
You can write a script to svn update for you every time, and scrap the revision number from the update's output into a file. The following bash script should more or less do it:
#!/bin/bash
svn --non-interactive update ..
svn --non-interactive update .. | perl -p -e "s/.* revision ([\d]*)\./\$1/" > ../version.phtml;
I implemented a clumsy (but relatively thorough) implementation of Subversion 1.7 revision retrieval in TheHostingTool. Check the commit message for an explanation. The function is contained in class_main.php which is one directory after /trunk (/trunk/includes/class_main.php). You'll need to adjust relative paths for your specific needs. This is a slightly modified version of the function found in class_main.php for use elsewhere.
public function getSubversionRevision() {
// This will work for Subverson 1.6 clients and below
if(file_exists("../.svn/entries")) {
$svn = File("../.svn/entries");
return (int)$svn[3];
}
// Check the previous directories recursively looking for wc.db (Subversion 1.7)
$searchDepth = 3; // Max search depth
// Do we have PDO? And do we have the SQLite PDO driver?
if(!extension_loaded('PDO') || !extension_loaded('pdo_sqlite')) {
$searchDepth = 0; // Don't even bother...
}
for($i = 1; $i <= $searchDepth; $i++) {
$dotdot .= '../';
if(!file_exists("$dotdot.svn/wc.db")) {
continue;
}
$wcdb = new PDO("sqlite:$dotdot.svn/wc.db");
$result = $wcdb->query('SELECT "revision" FROM "NODES" WHERE "repos_path" = "'.basename(realpath('..')).'"');
return (int)$result->fetchColumn();
}
if($this->canRun('exec')) {
exec('svnversion ' . realpath('..'), $out, $return);
// For this to work, svnversion must be in your PHP's PATH enviroment variable
if($return === 0 && $out[0] != "Unversioned directory") {
return (int)$out[0];
}
}
return false;
}
Instead of .= '../' you may want to use str_repeat if you don't start at 1. Or, you could simply define $dotdot ahead of time to wherever you would like to start.
Or just query:
SELECT "changed_revision" FROM "NODES" ORDER BY changed_revision DESC LIMIT 1;
if you wonder the last revision of the whole repo! :)
Excuse me, but if you want portable and bullet-proof solution, why not call Subversion CLI inside PHP?
You can use svn info inside any directory of WC (capture, parse output and get a set of data) of svnversion if you want to get only global revision

Store information about a directory

Other than the foldername, is there a way to get/set information about a directory to the actual folder itself?
I want to set a directory priority so folders are displayed in a certain order by assigning a number to each.
This is possible with Extended File Attributes:
https://secure.wikimedia.org/wikipedia/en/wiki/Extended_file_attributes
Extended file attributes is a file system feature that enables users to associate computer files with metadata not interpreted by the filesystem, whereas regular attributes have a purpose strictly defined by the filesystem (such as permissions or records of creation and modification times).
Try the xattr API to get/set them:
http://docs.php.net/manual/en/book.xattr.php
Example from Manual:
$file = 'my_favourite_song.wav';
xattr_set($file, 'Artist', 'Someone');
xattr_set($file, 'My ranking', 'Good');
xattr_set($file, 'Listen count', '34');
/* ... other code ... */
printf("You've played this song %d times", xattr_get($file, 'Listen count'));
You can do it for NTFS for sure: http://en.wikipedia.org/wiki/NTFS#Alternate_data_streams_.28ADS.29
Don't know if such a feature exist for *nix file systems.
Why do you want to anchor your program logic in the filesystem of the OS? That isn't a proper way to store such a information. One reason is that you leave your application domain and other programs could override your saved information.
Or if you move your application to a newer server, you may run in trouble that you cant transfer this information (e.g. as the new environment has another filesystem).
It is also bad practice to suppose a specific filesystem where your application is running.
A better way is to store this in your application (e.g. database if you need it persistent).
A simple array can do this job, with key as priority and value an array with objects of Directory for example.
It could look like this:
array(
0 => array( // highest prio
0 => DirObject,
1 => DirObject,
2 => DirObject
),
1 => array(
0 => DirObject,
1 => DirObject,
...
), ...
Then you can present your folders with an flatten function or a simple foreach. And can easily save it as serialized/jsoned string in a database.

Categories