I'm trying to recursively list every file that is in my bucket. It's not too many files but I'd like to list them to test a few things. This code works on a normal file system but it's not working on Google Cloud Storage.
Anyone have any suggestions?
function recurse_look($src) {
$dir = opendir($src);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) {
if ( is_dir($src . '/' . $file) ) {
recurse_look($src . '/' . $file);
}
else {
echo $src . '/' . $file;
echo "<br />";
}
}
}
closedir($dir);
}
recurse_look("gs://<BUCKET>");
Personally, I would recommend not using a filesystem-impersonation abstraction layer on top of Google Cloud Storage, for a task such as listing everything inside a bucket -- rather, just reach out for the underlying functionality.
In particular, see https://cloud.google.com/storage/docs/json_api/v1/json-api-php-samples for everything about authentication etc, and, once, that's taken care of, focus on just one line in the example:
$objects = $storageService->objects->listObjects(DEFAULT_BUCKET);
This is all you need to list all objects in a bucket (which is not the same thing as "files in a directory", and the "filesystem simulations" on top of buckets and objects, I offer as being just my personal opinion, end up hurting rather than helping despite their excellent intentions:-).
Now if the objects' names contain e.g slashes and you want to take that into account as symbolically signifying something or other, go right ahead, but at least this way you're sure you're getting all the objects actually existing in the bucket, and, nothing but those!-)
Now that glob is working, you can try something like this
function lstree($dir) {
foreach (glob($dir . '/*') as $path) {
if (is_dir($path)) {
echo $path;
lstree($path);
} else {
echo $path;
}
}
lstree('gs://{bucket}/');
Related
I have this code that copies files and is there a possibility of getting progress of how much has been copied?
<?php
$src = '../www/';
$dst = '../../backup/';
function recurse_copy($src,$dst) {
$dir = opendir($src);
#mkdir($dst);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) {
if ( is_dir($src . '/' . $file) ) {
recurse_copy($src . '/' . $file,$dst . '/' . $file);
}else {
copy($src . '/' . $file,$dst . '/' . $file);
}
}
}
closedir($dir);
}
recurse_copy($src,$dst);
}
?>
And if it is possible to get that number by ajax response. That means that response has to be sent multiple times. But I don't know how to do that.
You can track the copied files using a third argument passed by reference.
function recurse_copy($src, $dst, &$copied) {
// recurse code
$copied[] = [ 'src' => $src, 'dst' => $dst, 'file' => $file ];
copy($src.'/'.$file, $dst.'/'.$file);
}
$copied = [];
recurse_copy($src, $dst, $copied);
print_r($copied);
Other ways might be closures (function assigned to variable) and the use statement or class-properties when you put your function in a class.
Edit
For progress as in live update, see echo and flush() to see semi-live which files are beeing copied. A progress within a file copy is not possible.
There are two ways:
Knowing how many files you are going to copy, so that you can show a %
Not knowing the total number of files
In the first case, you have to get the full list of files first and then do the copying. Depending on the size of the directory tree and number of files, it can add quite some overhead, but it has its benefits. You have to decide.
In any case, you have to add a third parameter to the function:
function recurse_copy($src, $dst, callable $progress_callback = function(){}) { ... }
Bear in mind that callable is only supported from PHP 5.4 onwards.
The signature of the callback function would be:
function handle_progress($action, $data) { ... }
Then you can invoke the callback function like this:
$progress_callback('start'); // or...
$progress_callback('start', ['total' => $numfiles]);
$progress_callback('progress', ['current' => $filename]); // or...
$progress_callback('progress', ['total' => $numfiles, 'current' => $numcurrent, 'currentfile' => $filename]);
$progress_callback('finish');
You decide which data to pass to the progress callback and what to do with it once in the handler.
Now, to be able to get the progress via AJAX, you have to create a task that runs independently of the HTTP request. You return the task ID, and with AJAX you poll the progress of that ID.
In the server, you would have to use some kind of queue/task system, e.g. Laravel queues. It's only an example; you can google for more.
In the function callback, you can save to disk/redis/whatever the progress of the current task.
I'm writing a build/deploy script using a CLI php script.
Say I have a directory /environment and in it there are simply two broken symlinks.
I'm running glob(/environment/{,.}*). When I foreach over the glob, all I see are . and ... The symlinks never show up in the list.
How can you loop over a directory, detect broken symlinks, and unlink() them using PHP?
On a broken symlink is_link() returns true and file_exists() returns false.
Since glob() does not list broken symlinks, you have to list the contents in a different way.
Here is an example using scandir()
foreach(scandir($dir) as $entry) {
$path = $dir . DIRECTORY_SEPARATOR . $entry;
if (is_link($path) && !file_exists($path)) {
#unlink($path);
}
}
use realpath function:
foreach(scandir($dir) as $entry) {
$path = $dir . DIRECTORY_SEPARATOR . $entry;
if (!realpath($path)) {
#unlink($path);
}
}
I'm making a Wordpress theme, basically for portfolios.
Making plugins into the theme is bad, since changing themes can become a problem for the user and yourself if you do so. So I'm cooking up some script, that takes a plugins folder I made in my theme, which has the plugins that I would have built into the theme, but I'm making them install themselves when you select my theme. So these plugins will be updatable through the dashboard, and auto installed (if not already installed), into the site. Good idea no? (I got it from a forums post, but I dont think its been done as far as I know).
So I have a plugins folder in my theme, which has the plugins I want to auto install. I want to copy the plugins(single files or directories) into the wp-content/plugins folder and then install/activate them.
The problem is when I try to copy, it gives an error
Warning: copy(http://127.0.0.1/inside-theme/wordpress/wp-content/plugins): failed to open stream: HTTP wrapper does not support writeable connections in C:\**path-to-www-**\www\inside-theme\wordpress\wp-content\themes\Inside Theme\header.php on line 105
If you're wondering about why it's in header.php, I'm just doing this for testing purposes to see if it copies. I will put it in a hook after.
Here is my code I'm using to copy the plugins,
$dir = get_template_directory() . '/plugins/'; // the plugins folder in the theme
$plugins_in_theme = scandir($dir); // $dir's contents
$plugins_dir = plugins_url(); // url to the wp-content/plugins/
print_r($plugins_in_theme); // just to check the output, not important
foreach ($plugins_in_theme as $plugin) {
if ($plugin != '.' || '..') {
if (!file_exists($plugins_dir . $plugin)) {
if (is_dir($plugin)) {
recurse_copy($dir . $plugin, $plugins_dir);
} else {
copy($dir . $plugin, $plugins_dir);
}
}
}
}
recurse_copy() is a function I picked up off another stackoverflow question for copying directories since copy() only copies files, not folders. Also note that, it gives multiple errors, with the functions.php of my theme mentioned in most errors, which is where I put the recursive_copy() function. (Is that ok? It's my first theme..)
function recurse_copy($src,$dst) { //for copying directories
$dir = opendir($src);
#mkdir($dst);
while(false !== ( $file = readdir($dir)) ) {
if (( $file != '.' ) && ( $file != '..' )) {
if ( is_dir($src . '/' . $file) ) {
recurse_copy($src . '/' . $file,$dst . '/' . $file);
}
else {
copy($src . '/' . $file,$dst . '/' . $file);
}
}
}
closedir($dir);
}
So how can I remove this error and get it to work?
Extra details,
I'm using windows xp and I'm using the 'handcrafted wp' parent theme, I AM RUNNING THIS LOCALLY. (on local host)
Hope I was clear.
You are using $plugins_dir = plugins_url(); in the code which returns http://yoursite/wp-content/plugins/ However, copy function works with directories not URLs, so it's better to use, ABSPATH, dirname( __FILE__ ) . '/blablabla.php' and other functions returning directories not URLs. Click here to learn more about PHP copy function
Beginner : I cant seem to get my head around the logic of it. Have searched but seems to come up with listing files and folders from an actual directory ie. (opendir).
My problem is :
Im trying to work out (in PHP) how to list files and subfolders from a path stored in a database. (Without any access to the file or dir, so just from the path name)
For example database shows:
main/home/television.jpg
main/home/sofa.jpg
main/home/bedroom/bed.jpg
main/home/bedroom/lamp.jpg
So if i specify main/home - it shows: television.jpg, sofa.jpg and the name of the subfolder : bedroom.
scanFolder('main/home');
function scanFolder($dir) {
foreach (scandir($dir) as $file) {
if (!in_array($file, array('.', '..'))) {
if (is_dir($file)) {
scanFolder($dir . '/' . $file);
}
else {
echo $dir . '/' . $file . "\n";
}
}
}
}
You would probably want to check on each iteration if the filename is a directory or not. If it is, open it up and read its contents and output them. A recursive function would work best in this situation.
http://php.net/manual/en/function.is-dir.php
Does anyone know a solution to this problem? I'm unable to open a subdirectory within a symboliclink'd directory. I've confirmed that the paths are correct (even copy & pasted the path into explorer, which parsed it fine). This is a strange, annoying, bug :|.
Example:
C:\folder\symbolic_link\dir1\dir2 - opening dir2 fails.
C:\folder\symbolic_link\dir1 - works
C:\folder\real_directory\dir1\dir2 - works
C:\folder\real_directory\dir1 - works
Alright, I finally found a hack to solve this bug in php's handling of symlinks on windows. The bug occurs when recursively iterating through files/directories using opendir(). If a symlink to a directory exists in the current directory, opendir() will fail to read the directories in the directory symlink. It is caused by something funky in php's statcache, and can be resolved by calling clearstatcache() before calling opendir() on the directory symlink (also, the parent directory's file-handle must be closed).
Here is an example of the fix:
<?php
class Filesystem
{
public static function files($path, $stats = FALSE)
{
clearstatcache();
$ret = array();
$handle = opendir($path);
$files = array();
// Store files in directory, subdirectories can't be read until current handle is closed & statcache cleared.
while (FALSE !== ($file = readdir($handle)))
{
if ($file != '.' && $file != '..')
{
$files[] = $file;
}
}
// Handle _must_ be closed before statcache is cleared, cache from open handles won't be cleared!
closedir($handle);
foreach ($files as $file)
{
clearstatcache($path);
if (is_dir($path . '/' . $file))
{
$dir_files = self::files($path . '/' . $file);
foreach ($dir_files as $dir_file)
{
$ret[] = $file . '/' . $dir_file;
}
}
else if (is_file($path . '/' . $file))
{
$ret[] = $file;
}
}
return $ret;
}
}
var_dump(filessystem::files('c:\\some_path'));
Edit: It seems that clearstatcache($path) must be called before any file-handling functions on the symlink'd dir. Php isn't caching symlink'd dirs properly.