updated core to 7.58 (right after the site was hacked)
This commit is contained in:
13
sites/all/modules/examples/file_example/file_example.info
Normal file
13
sites/all/modules/examples/file_example/file_example.info
Normal file
@@ -0,0 +1,13 @@
|
||||
name = File example
|
||||
description = Examples of using the Drupal File API and Stream Wrappers.
|
||||
package = Example modules
|
||||
core = 7.x
|
||||
files[] = file_example_session_streams.inc
|
||||
files[] = file_example.test
|
||||
|
||||
; Information added by Drupal.org packaging script on 2017-01-10
|
||||
version = "7.x-1.x-dev"
|
||||
core = "7.x"
|
||||
project = "examples"
|
||||
datestamp = "1484076787"
|
||||
|
570
sites/all/modules/examples/file_example/file_example.module
Normal file
570
sites/all/modules/examples/file_example/file_example.module
Normal file
@@ -0,0 +1,570 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Examples demonstrating the Drupal File API (and Stream Wrappers).
|
||||
*/
|
||||
|
||||
/**
|
||||
* @defgroup file_example Example: Files
|
||||
* @ingroup examples
|
||||
* @{
|
||||
* Examples demonstrating the Drupal File API (and Stream Wrappers).
|
||||
*
|
||||
* The File Example module is a part of the Examples for Developers Project
|
||||
* and provides various Drupal File API Examples. You can download and
|
||||
* experiment with this code at the
|
||||
* @link http://drupal.org/project/examples Examples for Developers project page. @endlink
|
||||
*
|
||||
* See @link http://drupal.org/node/555118 Drupal File API @endlink for handbook
|
||||
* documentation on the File API and
|
||||
* @link file File summary on api.drupal.org @endlink for the function summary.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Implements hook_menu().
|
||||
*
|
||||
* Set up the URLs (menu entries) for the file examples.
|
||||
*/
|
||||
function file_example_menu() {
|
||||
$items = array();
|
||||
$items['examples/file_example'] = array(
|
||||
'title' => 'File Example',
|
||||
'page callback' => 'file_example_intro',
|
||||
'access callback' => TRUE,
|
||||
'expanded' => TRUE,
|
||||
);
|
||||
$items['examples/file_example/fileapi'] = array(
|
||||
'title' => 'Use File API to read/write a file',
|
||||
'page callback' => 'drupal_get_form',
|
||||
'access arguments' => array('use file example'),
|
||||
'page arguments' => array('file_example_readwrite'),
|
||||
);
|
||||
$items['examples/file_example/access_session'] = array(
|
||||
'page callback' => 'file_example_session_contents',
|
||||
'access arguments' => array('use file example'),
|
||||
'type' => MENU_CALLBACK,
|
||||
);
|
||||
return $items;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implements hook_permission().
|
||||
*/
|
||||
function file_example_permission() {
|
||||
return array(
|
||||
'use file example' => array(
|
||||
'title' => t('Use the examples in the File Example module'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple introduction to the workings of this module.
|
||||
*/
|
||||
function file_example_intro() {
|
||||
$markup = t('The file example module provides a form and code to demonstrate the Drupal 7 file api. Experiment with the form, and then look at the submit handlers in the code to understand the file api.');
|
||||
return array('#markup' => $markup);
|
||||
}
|
||||
/**
|
||||
* Form builder function.
|
||||
*
|
||||
* A simple form that allows creation of a file, managed or unmanaged. It
|
||||
* also allows reading/deleting a file and creation of a directory.
|
||||
*/
|
||||
function file_example_readwrite($form, &$form_state) {
|
||||
if (empty($_SESSION['file_example_default_file'])) {
|
||||
$_SESSION['file_example_default_file'] = 'session://drupal.txt';
|
||||
}
|
||||
$default_file = $_SESSION['file_example_default_file'];
|
||||
if (empty($_SESSION['file_example_default_directory'])) {
|
||||
$_SESSION['file_example_default_directory'] = 'session://directory1';
|
||||
}
|
||||
$default_directory = $_SESSION['file_example_default_directory'];
|
||||
|
||||
$form['write_file'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Write to a file'),
|
||||
);
|
||||
$form['write_file']['write_contents'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Enter something you would like to write to a file') . ' ' . date('m'),
|
||||
'#default_value' => t('Put some text here or just use this text'),
|
||||
);
|
||||
|
||||
$form['write_file']['destination'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $default_file,
|
||||
'#title' => t('Optional: Enter the streamwrapper saying where it should be written'),
|
||||
'#description' => t('This may be public://some_dir/test_file.txt or private://another_dir/some_file.txt, for example. If you include a directory, it must already exist. The default is "public://". Since this example supports session://, you can also use something like session://somefile.txt.'),
|
||||
);
|
||||
|
||||
$form['write_file']['managed_submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Write managed file'),
|
||||
'#submit' => array('file_example_managed_write_submit'),
|
||||
);
|
||||
$form['write_file']['unmanaged_submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Write unmanaged file'),
|
||||
'#submit' => array('file_example_unmanaged_write_submit'),
|
||||
);
|
||||
$form['write_file']['unmanaged_php'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Unmanaged using PHP'),
|
||||
'#submit' => array('file_example_unmanaged_php_submit'),
|
||||
);
|
||||
|
||||
$form['fileops'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Read from a file'),
|
||||
);
|
||||
$form['fileops']['fileops_file'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#default_value' => $default_file,
|
||||
'#title' => t('Enter the URI of a file'),
|
||||
'#description' => t('This must be a stream-type description like public://some_file.txt or http://drupal.org or private://another_file.txt or (for this example) session://yet_another_file.txt.'),
|
||||
);
|
||||
$form['fileops']['read_submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Read the file and store it locally'),
|
||||
'#submit' => array('file_example_read_submit'),
|
||||
);
|
||||
$form['fileops']['delete_submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Delete file'),
|
||||
'#submit' => array('file_example_delete_submit'),
|
||||
);
|
||||
$form['fileops']['check_submit'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Check to see if file exists'),
|
||||
'#submit' => array('file_example_file_check_exists_submit'),
|
||||
);
|
||||
|
||||
$form['directory'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Create or prepare a directory'),
|
||||
);
|
||||
|
||||
$form['directory']['directory_name'] = array(
|
||||
'#type' => 'textfield',
|
||||
'#title' => t('Directory to create/prepare/delete'),
|
||||
'#default_value' => $default_directory,
|
||||
'#description' => t('This is a directory as in public://some/directory or private://another/dir.'),
|
||||
);
|
||||
$form['directory']['create_directory'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Create directory'),
|
||||
'#submit' => array('file_example_create_directory_submit'),
|
||||
);
|
||||
$form['directory']['delete_directory'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Delete directory'),
|
||||
'#submit' => array('file_example_delete_directory_submit'),
|
||||
);
|
||||
$form['directory']['check_directory'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Check to see if directory exists'),
|
||||
'#submit' => array('file_example_check_directory_submit'),
|
||||
);
|
||||
|
||||
$form['debug'] = array(
|
||||
'#type' => 'fieldset',
|
||||
'#title' => t('Debugging'),
|
||||
);
|
||||
$form['debug']['show_raw_session'] = array(
|
||||
'#type' => 'submit',
|
||||
'#value' => t('Show raw $_SESSION contents'),
|
||||
'#submit' => array('file_example_show_session_contents_submit'),
|
||||
);
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler to write a managed file.
|
||||
*
|
||||
* The key functions used here are:
|
||||
* - file_save_data(), which takes a buffer and saves it to a named file and
|
||||
* also creates a tracking record in the database and returns a file object.
|
||||
* In this function we use FILE_EXISTS_RENAME (the default) as the argument,
|
||||
* which means that if there's an existing file, create a new non-colliding
|
||||
* filename and use it.
|
||||
* - file_create_url(), which converts a URI in the form public://junk.txt or
|
||||
* private://something/test.txt into a URL like
|
||||
* http://example.com/sites/default/files/junk.txt.
|
||||
*/
|
||||
function file_example_managed_write_submit($form, &$form_state) {
|
||||
$data = $form_state['values']['write_contents'];
|
||||
$uri = !empty($form_state['values']['destination']) ? $form_state['values']['destination'] : NULL;
|
||||
|
||||
// Managed operations work with a file object.
|
||||
$file_object = file_save_data($data, $uri, FILE_EXISTS_RENAME);
|
||||
if (!empty($file_object)) {
|
||||
$url = file_create_url($file_object->uri);
|
||||
$_SESSION['file_example_default_file'] = $file_object->uri;
|
||||
drupal_set_message(
|
||||
t('Saved managed file: %file to destination %destination (accessible via !url, actual uri=<span id="uri">@uri</span>)',
|
||||
array(
|
||||
'%file' => print_r($file_object, TRUE),
|
||||
'%destination' => $uri, '@uri' => $file_object->uri,
|
||||
'!url' => l(t('this URL'), $url),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Failed to save the managed file'), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler to write an unmanaged file.
|
||||
*
|
||||
* The key functions used here are:
|
||||
* - file_unmanaged_save_data(), which takes a buffer and saves it to a named
|
||||
* file, but does not create any kind of tracking record in the database.
|
||||
* This example uses FILE_EXISTS_REPLACE for the third argument, meaning
|
||||
* that if there's an existing file at this location, it should be replaced.
|
||||
* - file_create_url(), which converts a URI in the form public://junk.txt or
|
||||
* private://something/test.txt into a URL like
|
||||
* http://example.com/sites/default/files/junk.txt.
|
||||
*/
|
||||
function file_example_unmanaged_write_submit($form, &$form_state) {
|
||||
$data = $form_state['values']['write_contents'];
|
||||
$destination = !empty($form_state['values']['destination']) ? $form_state['values']['destination'] : NULL;
|
||||
|
||||
// With the unmanaged file we just get a filename back.
|
||||
$filename = file_unmanaged_save_data($data, $destination, FILE_EXISTS_REPLACE);
|
||||
if ($filename) {
|
||||
$url = file_create_url($filename);
|
||||
$_SESSION['file_example_default_file'] = $filename;
|
||||
drupal_set_message(
|
||||
t('Saved file as %filename (accessible via !url, uri=<span id="uri">@uri</span>)',
|
||||
array(
|
||||
'%filename' => $filename,
|
||||
'@uri' => $filename,
|
||||
'!url' => l(t('this URL'), $url),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Failed to save the file'), 'error');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler to write an unmanaged file using plain PHP functions.
|
||||
*
|
||||
* The key functions used here are:
|
||||
* - file_unmanaged_save_data(), which takes a buffer and saves it to a named
|
||||
* file, but does not create any kind of tracking record in the database.
|
||||
* - file_create_url(), which converts a URI in the form public://junk.txt or
|
||||
* private://something/test.txt into a URL like
|
||||
* http://example.com/sites/default/files/junk.txt.
|
||||
* - drupal_tempnam() generates a temporary filename for use.
|
||||
*/
|
||||
function file_example_unmanaged_php_submit($form, &$form_state) {
|
||||
$data = $form_state['values']['write_contents'];
|
||||
$destination = !empty($form_state['values']['destination']) ? $form_state['values']['destination'] : NULL;
|
||||
|
||||
if (empty($destination)) {
|
||||
// If no destination has been provided, use a generated name.
|
||||
$destination = drupal_tempnam('public://', 'file');
|
||||
}
|
||||
|
||||
// With all traditional PHP functions we can use the stream wrapper notation
|
||||
// for a file as well.
|
||||
$fp = fopen($destination, 'w');
|
||||
|
||||
// To demonstrate the fact that everything is based on streams, we'll do
|
||||
// multiple 5-character writes to put this to the file. We could easily
|
||||
// (and far more conveniently) write it in a single statement with
|
||||
// fwrite($fp, $data).
|
||||
$length = strlen($data);
|
||||
$write_size = 5;
|
||||
for ($i = 0; $i < $length; $i += $write_size) {
|
||||
$result = fwrite($fp, substr($data, $i, $write_size));
|
||||
if ($result === FALSE) {
|
||||
drupal_set_message(t('Failed writing to the file %file', array('%file' => $destination)), 'error');
|
||||
fclose($fp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
$url = file_create_url($destination);
|
||||
$_SESSION['file_example_default_file'] = $destination;
|
||||
drupal_set_message(
|
||||
t('Saved file as %filename (accessible via !url, uri=<span id="uri">@uri</span>)',
|
||||
array(
|
||||
'%filename' => $destination,
|
||||
'@uri' => $destination,
|
||||
'!url' => l(t('this URL'), $url),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for reading a stream wrapper.
|
||||
*
|
||||
* Drupal now has full support for PHP's stream wrappers, which means that
|
||||
* instead of the traditional use of all the file functions
|
||||
* ($fp = fopen("/tmp/some_file.txt");) far more sophisticated and generalized
|
||||
* (and extensible) things can be opened as if they were files. Drupal itself
|
||||
* provides the public:// and private:// schemes for handling public and
|
||||
* private files. PHP provides file:// (the default) and http://, so that a
|
||||
* URL can be read or written (as in a POST) as if it were a file. In addition,
|
||||
* new schemes can be provided for custom applications, as will be demonstrated
|
||||
* below.
|
||||
*
|
||||
* Here we take the stream wrapper provided in the form. We grab the
|
||||
* contents with file_get_contents(). Notice that's it's as simple as that:
|
||||
* file_get_contents("http://example.com") or
|
||||
* file_get_contents("public://somefile.txt") just works. Although it's
|
||||
* not necessary, we use file_unmanaged_save_data() to save this file locally
|
||||
* and then find a local URL for it by using file_create_url().
|
||||
*/
|
||||
function file_example_read_submit($form, &$form_state) {
|
||||
$uri = $form_state['values']['fileops_file'];
|
||||
|
||||
if (!is_file($uri)) {
|
||||
drupal_set_message(t('The file %uri does not exist', array('%uri' => $uri)), 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a working filename to save this by stripping off the (possible)
|
||||
// file portion of the streamwrapper. If it's an evil file extension,
|
||||
// file_munge_filename() will neuter it.
|
||||
$filename = file_munge_filename(preg_replace('@^.*/@', '', $uri), '', TRUE);
|
||||
$buffer = file_get_contents($uri);
|
||||
|
||||
if ($buffer) {
|
||||
$sourcename = file_unmanaged_save_data($buffer, 'public://' . $filename);
|
||||
if ($sourcename) {
|
||||
$url = file_create_url($sourcename);
|
||||
$_SESSION['file_example_default_file'] = $sourcename;
|
||||
drupal_set_message(
|
||||
t('The file was read and copied to %filename which is accessible at !url',
|
||||
array(
|
||||
'%filename' => $sourcename,
|
||||
'!url' => l($url, $url),
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Failed to save the file'));
|
||||
}
|
||||
}
|
||||
else {
|
||||
// We failed to get the contents of the requested file.
|
||||
drupal_set_message(t('Failed to retrieve the file %file', array('%file' => $uri)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler to delete a file.
|
||||
*/
|
||||
function file_example_delete_submit($form, &$form_state) {
|
||||
|
||||
$uri = $form_state['values']['fileops_file'];
|
||||
|
||||
// Since we don't know if the file is managed or not, look in the database
|
||||
// to see. Normally, code would be working with either managed or unmanaged
|
||||
// files, so this is not a typical situation.
|
||||
$file_object = file_example_get_managed_file($uri);
|
||||
|
||||
// If a managed file, use file_delete().
|
||||
if (!empty($file_object)) {
|
||||
$result = file_delete($file_object);
|
||||
if ($result !== TRUE) {
|
||||
drupal_set_message(t('Failed deleting managed file %uri. Result was %result',
|
||||
array(
|
||||
'%uri' => $uri,
|
||||
'%result' => print_r($result, TRUE),
|
||||
)
|
||||
), 'error');
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Successfully deleted managed file %uri', array('%uri' => $uri)));
|
||||
$_SESSION['file_example_default_file'] = $uri;
|
||||
}
|
||||
}
|
||||
// Else use file_unmanaged_delete().
|
||||
else {
|
||||
$result = file_unmanaged_delete($uri);
|
||||
if ($result !== TRUE) {
|
||||
drupal_set_message(t('Failed deleting unmanaged file %uri', array('%uri' => $uri, 'error')));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Successfully deleted unmanaged file %uri', array('%uri' => $uri)));
|
||||
$_SESSION['file_example_default_file'] = $uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler to check existence of a file.
|
||||
*/
|
||||
function file_example_file_check_exists_submit($form, &$form_state) {
|
||||
$uri = $form_state['values']['fileops_file'];
|
||||
if (is_file($uri)) {
|
||||
drupal_set_message(t('The file %uri exists.', array('%uri' => $uri)));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('The file %uri does not exist.', array('%uri' => $uri)));
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* Submit handler for directory creation.
|
||||
*
|
||||
* Here we create a directory and set proper permissions on it using
|
||||
* file_prepare_directory().
|
||||
*/
|
||||
function file_example_create_directory_submit($form, &$form_state) {
|
||||
$directory = $form_state['values']['directory_name'];
|
||||
|
||||
// The options passed to file_prepare_directory are a bitmask, so we can
|
||||
// specify either FILE_MODIFY_PERMISSIONS (set permissions on the directory),
|
||||
// FILE_CREATE_DIRECTORY, or both together:
|
||||
// FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY.
|
||||
// FILE_MODIFY_PERMISSIONS will set the permissions of the directory by
|
||||
// by default to 0755, or to the value of the variable 'file_chmod_directory'.
|
||||
if (!file_prepare_directory($directory, FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY)) {
|
||||
drupal_set_message(t('Failed to create %directory.', array('%directory' => $directory)), 'error');
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Directory %directory is ready for use.', array('%directory' => $directory)));
|
||||
$_SESSION['file_example_default_directory'] = $directory;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler for directory deletion.
|
||||
*
|
||||
* @see file_unmanaged_delete_recursive()
|
||||
*/
|
||||
function file_example_delete_directory_submit($form, &$form_state) {
|
||||
$directory = $form_state['values']['directory_name'];
|
||||
|
||||
$result = file_unmanaged_delete_recursive($directory);
|
||||
if (!$result) {
|
||||
drupal_set_message(t('Failed to delete %directory.', array('%directory' => $directory)), 'error');
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Recursively deleted directory %directory.', array('%directory' => $directory)));
|
||||
$_SESSION['file_example_default_directory'] = $directory;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit handler to test directory existence.
|
||||
*
|
||||
* This actually just checks to see if the directory is writable
|
||||
*
|
||||
* @param array $form
|
||||
* FormAPI form.
|
||||
* @param array $form_state
|
||||
* FormAPI form state.
|
||||
*/
|
||||
function file_example_check_directory_submit($form, &$form_state) {
|
||||
$directory = $form_state['values']['directory_name'];
|
||||
$result = is_dir($directory);
|
||||
if (!$result) {
|
||||
drupal_set_message(t('Directory %directory does not exist.', array('%directory' => $directory)));
|
||||
}
|
||||
else {
|
||||
drupal_set_message(t('Directory %directory exists.', array('%directory' => $directory)));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility submit function to show the contents of $_SESSION.
|
||||
*/
|
||||
function file_example_show_session_contents_submit($form, &$form_state) {
|
||||
// If the devel module is installed, use it's nicer message format.
|
||||
if (module_exists('devel')) {
|
||||
dsm($_SESSION['file_example'], t('Entire $_SESSION["file_example"]'));
|
||||
}
|
||||
else {
|
||||
drupal_set_message('<pre>' . print_r($_SESSION['file_example'], TRUE) . '</pre>');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function to check for and return a managed file.
|
||||
*
|
||||
* In this demonstration code we don't necessarily know if a file is managed
|
||||
* or not, so often need to check to do the correct behavior. Normal code
|
||||
* would not have to do this, as it would be working with either managed or
|
||||
* unmanaged files.
|
||||
*
|
||||
* @param string $uri
|
||||
* The URI of the file, like public://test.txt.
|
||||
*/
|
||||
function file_example_get_managed_file($uri) {
|
||||
$fid = db_query('SELECT fid FROM {file_managed} WHERE uri = :uri', array(':uri' => $uri))->fetchField();
|
||||
if (!empty($fid)) {
|
||||
$file_object = file_load($fid);
|
||||
return $file_object;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements hook_stream_wrappers().
|
||||
*
|
||||
* hook_stream_wrappers() is Drupal's way of exposing the class that PHP will
|
||||
* use to provide a new stream wrapper class. In this case, we'll expose the
|
||||
* 'session' scheme, so a file reference like "session://example/example.txt"
|
||||
* is readable and writable as a location in the $_SESSION variable.
|
||||
*
|
||||
* @see FileExampleSessionStreamWrapper
|
||||
*/
|
||||
function file_example_stream_wrappers() {
|
||||
$wrappers = array(
|
||||
'session' => array(
|
||||
'name' => t('Example: $_SESSION variable storage'),
|
||||
'class' => 'FileExampleSessionStreamWrapper',
|
||||
'description' => t('Store files in the $_SESSION variable as an example.'),
|
||||
),
|
||||
);
|
||||
return $wrappers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the contents of a session file.
|
||||
*
|
||||
* This page callback function is called by the Menu API for the path
|
||||
* examples/file_example/access_session. Any extra path elements
|
||||
* beyond this are considered to be the session path. E.g.:
|
||||
* examples/file_example/access_session/foo/bar.txt would be the
|
||||
* equivalent of session://foo/bar.txt, which will map into
|
||||
* $_SESSION as keys: $_SESSION['foo']['bar.txt']
|
||||
*
|
||||
* Menu API will pass in additional path elements as function arguments. You
|
||||
* can obtain these with func_get_args().
|
||||
*
|
||||
* @return string
|
||||
* A message containing the contents of the session file.
|
||||
*
|
||||
* @see file_get_contents()
|
||||
*/
|
||||
function file_example_session_contents() {
|
||||
$path_components = func_get_args();
|
||||
$session_path = 'session://' . implode('/', $path_components);
|
||||
$content = file_get_contents($session_path);
|
||||
if ($content !== FALSE) {
|
||||
return t('Contents of @path :',
|
||||
array('@path' => check_plain($session_path))) . ' ' .
|
||||
print_r($content, TRUE);
|
||||
}
|
||||
return t('Unable to load contents of: @path',
|
||||
array('@path' => check_plain($session_path)));
|
||||
}
|
||||
|
||||
/**
|
||||
* @} End of "defgroup file_example".
|
||||
*/
|
149
sites/all/modules/examples/file_example/file_example.test
Normal file
149
sites/all/modules/examples/file_example/file_example.test
Normal file
@@ -0,0 +1,149 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Tests for File Example.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Functional tests for the File Example module.
|
||||
*
|
||||
* @ingroup file_example
|
||||
*/
|
||||
class FileExampleTest extends DrupalWebTestCase {
|
||||
|
||||
protected $priviledgedUser;
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public static function getInfo() {
|
||||
return array(
|
||||
'name' => 'File Example Functionality',
|
||||
'description' => 'Test File Example features and sample streamwrapper.',
|
||||
'group' => 'Examples',
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function setUp() {
|
||||
parent::setUp(array('file_example'));
|
||||
$this->priviledgedUser = $this->drupalCreateUser(array('use file example'));
|
||||
$this->drupalLogin($this->priviledgedUser);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the basic File Example UI.
|
||||
*
|
||||
* - Create a directory to work with
|
||||
* - Foreach scheme create and read files using each of the three methods.
|
||||
*/
|
||||
public function testFileExampleBasic() {
|
||||
|
||||
$expected_text = array(
|
||||
t('Write managed file') => t('Saved managed file'),
|
||||
t('Write unmanaged file') => t('Saved file as'),
|
||||
t('Unmanaged using PHP') => t('Saved file as'),
|
||||
);
|
||||
// For each of the three buttons == three write types.
|
||||
$buttons = array(
|
||||
t('Write managed file'),
|
||||
t('Write unmanaged file'),
|
||||
t('Unmanaged using PHP'),
|
||||
);
|
||||
foreach ($buttons as $button) {
|
||||
// For each scheme supported by Drupal + the session:// wrapper.
|
||||
$schemes = array('public', 'private', 'temporary', 'session');
|
||||
foreach ($schemes as $scheme) {
|
||||
// Create a directory for use.
|
||||
$dirname = $scheme . '://' . $this->randomName(10);
|
||||
|
||||
// Directory does not yet exist; assert that.
|
||||
$edit = array(
|
||||
'directory_name' => $dirname,
|
||||
);
|
||||
$this->drupalPost('examples/file_example/fileapi', $edit, t('Check to see if directory exists'));
|
||||
$this->assertRaw(t('Directory %dirname does not exist', array('%dirname' => $dirname)), 'Verify that directory does not exist.');
|
||||
|
||||
$this->drupalPost('examples/file_example/fileapi', $edit, t('Create directory'));
|
||||
$this->assertRaw(t('Directory %dirname is ready for use', array('%dirname' => $dirname)));
|
||||
|
||||
$this->drupalPost('examples/file_example/fileapi', $edit, t('Check to see if directory exists'));
|
||||
$this->assertRaw(t('Directory %dirname exists', array('%dirname' => $dirname)), 'Verify that directory now does exist.');
|
||||
|
||||
// Create a file in the directory we created.
|
||||
$content = $this->randomName(30);
|
||||
$filename = $dirname . '/' . $this->randomName(30) . '.txt';
|
||||
|
||||
// Assert that the file we're about to create does not yet exist.
|
||||
$edit = array(
|
||||
'fileops_file' => $filename,
|
||||
);
|
||||
$this->drupalPost('examples/file_example/fileapi', $edit, t('Check to see if file exists'));
|
||||
$this->assertRaw(t('The file %filename does not exist', array('%filename' => $filename)), 'Verify that file does not yet exist.');
|
||||
|
||||
debug(
|
||||
t('Processing button=%button, scheme=%scheme, dir=%dirname, file=%filename',
|
||||
array(
|
||||
'%button' => $button,
|
||||
'%scheme' => $scheme,
|
||||
'%filename' => $filename,
|
||||
'%dirname' => $dirname,
|
||||
)
|
||||
)
|
||||
);
|
||||
$edit = array(
|
||||
'write_contents' => $content,
|
||||
'destination' => $filename,
|
||||
);
|
||||
$this->drupalPost('examples/file_example/fileapi', $edit, $button);
|
||||
$this->assertText($expected_text[$button]);
|
||||
|
||||
// Capture the name of the output file, as it might have changed due
|
||||
// to file renaming.
|
||||
$element = $this->xpath('//span[@id="uri"]');
|
||||
$output_filename = (string) $element[0];
|
||||
debug($output_filename, 'Name of output file');
|
||||
|
||||
// Click the link provided that is an easy way to get the data for
|
||||
// checking and make sure that the data we put in is what we get out.
|
||||
if (!in_array($scheme, array('private', 'temporary'))) {
|
||||
$this->clickLink(t('this URL'));
|
||||
$this->assertText($content);
|
||||
}
|
||||
|
||||
// Verify that the file exists.
|
||||
$edit = array(
|
||||
'fileops_file' => $filename,
|
||||
);
|
||||
$this->drupalPost('examples/file_example/fileapi', $edit, t('Check to see if file exists'));
|
||||
$this->assertRaw(t('The file %filename exists', array('%filename' => $filename)), 'Verify that file now exists.');
|
||||
|
||||
// Now read the file that got written above and verify that we can use
|
||||
// the writing tools.
|
||||
$edit = array(
|
||||
'fileops_file' => $output_filename,
|
||||
);
|
||||
$this->drupalPost('examples/file_example/fileapi', $edit, t('Read the file and store it locally'));
|
||||
|
||||
$this->assertText(t('The file was read and copied'));
|
||||
|
||||
$edit = array(
|
||||
'fileops_file' => $filename,
|
||||
);
|
||||
$this->drupalPost('examples/file_example/fileapi', $edit, t('Delete file'));
|
||||
$this->assertText(t('Successfully deleted'));
|
||||
$this->drupalPost('examples/file_example/fileapi', $edit, t('Check to see if file exists'));
|
||||
$this->assertRaw(t('The file %filename does not exist', array('%filename' => $filename)), 'Verify file has been deleted.');
|
||||
|
||||
$edit = array(
|
||||
'directory_name' => $dirname,
|
||||
);
|
||||
$this->drupalPost('examples/file_example/fileapi', $edit, t('Delete directory'));
|
||||
$this->drupalPost('examples/file_example/fileapi', $edit, t('Check to see if directory exists'));
|
||||
$this->assertRaw(t('Directory %dirname does not exist', array('%dirname' => $dirname)), 'Verify that directory does not exist after deletion.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,698 @@
|
||||
<?php
|
||||
/**
|
||||
* @file
|
||||
* Provides a demonstration session:// streamwrapper.
|
||||
*
|
||||
* This example is nearly fully functional, but has no known
|
||||
* practical use. It's an example and demonstration only.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Example stream wrapper class to handle session:// streams.
|
||||
*
|
||||
* This is just an example, as it could have horrible results if much
|
||||
* information were placed in the $_SESSION variable. However, it does
|
||||
* demonstrate both the read and write implementation of a stream wrapper.
|
||||
*
|
||||
* A "stream" is an important Unix concept for the reading and writing of
|
||||
* files and other devices. Reading or writing a "stream" just means that you
|
||||
* open some device, file, internet site, or whatever, and you don't have to
|
||||
* know at all what it is. All the functions that deal with it are the same.
|
||||
* You can read/write more from/to the stream, seek a position in the stream,
|
||||
* or anything else without the code that does it even knowing what kind
|
||||
* of device it is talking to. This Unix idea is extended into PHP's
|
||||
* mindset.
|
||||
*
|
||||
* The idea of "stream wrapper" is that this can be extended indefinitely.
|
||||
* The classic example is HTTP: With PHP you can do a
|
||||
* file_get_contents("http://drupal.org/projects") as if it were a file,
|
||||
* because the scheme "http" is supported natively in PHP. So Drupal adds
|
||||
* the public:// and private:// schemes, and contrib modules can add any
|
||||
* scheme they want to. This example adds the session:// scheme, which allows
|
||||
* reading and writing the $_SESSION['file_example'] key as if it were a file.
|
||||
*
|
||||
* Note that because this implementation uses simple PHP arrays ($_SESSION)
|
||||
* it is limited to string values, so binary files will not work correctly.
|
||||
* Only text files can be used.
|
||||
*
|
||||
* @ingroup file_example
|
||||
*/
|
||||
class FileExampleSessionStreamWrapper implements DrupalStreamWrapperInterface {
|
||||
/**
|
||||
* Stream context resource.
|
||||
*
|
||||
* @var Resource
|
||||
*/
|
||||
public $context;
|
||||
|
||||
|
||||
/**
|
||||
* Instance URI (stream).
|
||||
*
|
||||
* These streams will be references as 'session://example_target'
|
||||
*
|
||||
* @var String
|
||||
*/
|
||||
protected $uri;
|
||||
|
||||
/**
|
||||
* The content of the stream.
|
||||
*
|
||||
* Since this trivial example just uses the $_SESSION variable, this is
|
||||
* simply a reference to the contents of the related part of
|
||||
* $_SESSION['file_example'].
|
||||
*/
|
||||
protected $sessionContent;
|
||||
|
||||
/**
|
||||
* Pointer to where we are in a directory read.
|
||||
*/
|
||||
protected $directoryPointer;
|
||||
|
||||
/**
|
||||
* List of keys in a given directory.
|
||||
*/
|
||||
protected $directoryKeys;
|
||||
|
||||
/**
|
||||
* The pointer to the next read or write within the session variable.
|
||||
*/
|
||||
protected $streamPointer;
|
||||
|
||||
/**
|
||||
* Constructor method.
|
||||
*/
|
||||
public function __construct() {
|
||||
$_SESSION['file_example']['.isadir.txt'] = TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements setUri().
|
||||
*/
|
||||
public function setUri($uri) {
|
||||
$this->uri = $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements getUri().
|
||||
*/
|
||||
public function getUri() {
|
||||
return $this->uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements getTarget().
|
||||
*
|
||||
* The "target" is the portion of the URI to the right of the scheme.
|
||||
* So in session://example/test.txt, the target is 'example/test.txt'.
|
||||
*/
|
||||
public function getTarget($uri = NULL) {
|
||||
if (!isset($uri)) {
|
||||
$uri = $this->uri;
|
||||
}
|
||||
|
||||
list($scheme, $target) = explode('://', $uri, 2);
|
||||
|
||||
// Remove erroneous leading or trailing, forward-slashes and backslashes.
|
||||
// In the session:// scheme, there is never a leading slash on the target.
|
||||
return trim($target, '\/');
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements getMimeType().
|
||||
*/
|
||||
public static function getMimeType($uri, $mapping = NULL) {
|
||||
if (!isset($mapping)) {
|
||||
// The default file map, defined in file.mimetypes.inc is quite big.
|
||||
// We only load it when necessary.
|
||||
include_once DRUPAL_ROOT . '/includes/file.mimetypes.inc';
|
||||
$mapping = file_mimetype_mapping();
|
||||
}
|
||||
|
||||
$extension = '';
|
||||
$file_parts = explode('.', basename($uri));
|
||||
|
||||
// Remove the first part: a full filename should not match an extension.
|
||||
array_shift($file_parts);
|
||||
|
||||
// Iterate over the file parts, trying to find a match.
|
||||
// For my.awesome.image.jpeg, we try:
|
||||
// - jpeg
|
||||
// - image.jpeg, and
|
||||
// - awesome.image.jpeg
|
||||
while ($additional_part = array_pop($file_parts)) {
|
||||
$extension = drupal_strtolower($additional_part . ($extension ? '.' . $extension : ''));
|
||||
if (isset($mapping['extensions'][$extension])) {
|
||||
return $mapping['mimetypes'][$mapping['extensions'][$extension]];
|
||||
}
|
||||
}
|
||||
|
||||
return 'application/octet-stream';
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements getDirectoryPath().
|
||||
*
|
||||
* In this case there is no directory string, so return an empty string.
|
||||
*/
|
||||
public function getDirectoryPath() {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides getExternalUrl().
|
||||
*
|
||||
* We have set up a helper function and menu entry to provide access to this
|
||||
* key via HTTP; normally it would be accessible some other way.
|
||||
*/
|
||||
public function getExternalUrl() {
|
||||
$path = $this->getLocalPath();
|
||||
$url = url('examples/file_example/access_session/' . $path, array('absolute' => TRUE));
|
||||
return $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* We have no concept of chmod, so just return TRUE.
|
||||
*/
|
||||
public function chmod($mode) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements realpath().
|
||||
*/
|
||||
public function realpath() {
|
||||
return 'session://' . $this->getLocalPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the local path.
|
||||
*
|
||||
* Here we aren't doing anything but stashing the "file" in a key in the
|
||||
* $_SESSION variable, so there's not much to do but to create a "path"
|
||||
* which is really just a key in the $_SESSION variable. So something
|
||||
* like 'session://one/two/three.txt' becomes
|
||||
* $_SESSION['file_example']['one']['two']['three.txt'] and the actual path
|
||||
* is "one/two/three.txt".
|
||||
*
|
||||
* @param string $uri
|
||||
* Optional URI, supplied when doing a move or rename.
|
||||
*/
|
||||
protected function getLocalPath($uri = NULL) {
|
||||
if (!isset($uri)) {
|
||||
$uri = $this->uri;
|
||||
}
|
||||
|
||||
$path = str_replace('session://', '', $uri);
|
||||
$path = trim($path, '/');
|
||||
return $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens a stream, as for fopen(), file_get_contents(), file_put_contents().
|
||||
*
|
||||
* @param string $uri
|
||||
* A string containing the URI to the file to open.
|
||||
* @param string $mode
|
||||
* The file mode ("r", "wb" etc.).
|
||||
* @param int $options
|
||||
* A bit mask of STREAM_USE_PATH and STREAM_REPORT_ERRORS.
|
||||
* @param string &$opened_path
|
||||
* A string containing the path actually opened.
|
||||
*
|
||||
* @return bool
|
||||
* Returns TRUE if file was opened successfully. (Always returns TRUE).
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-open.php
|
||||
*/
|
||||
public function stream_open($uri, $mode, $options, &$opened_path) {
|
||||
$this->uri = $uri;
|
||||
// We make $session_content a reference to the appropriate key in the
|
||||
// $_SESSION variable. So if the local path were
|
||||
// /example/test.txt it $session_content would now be a
|
||||
// reference to $_SESSION['file_example']['example']['test.txt'].
|
||||
$this->sessionContent = &$this->uri_to_session_key($uri);
|
||||
|
||||
// Reset the stream pointer since this is an open.
|
||||
$this->streamPointer = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a reference to the correct $_SESSION key.
|
||||
*
|
||||
* @param string $uri
|
||||
* The uri: session://something
|
||||
* @param bool $create
|
||||
* If TRUE, create the key
|
||||
*
|
||||
* @return array|bool
|
||||
* A reference to the array at the end of the key-path, or
|
||||
* FALSE if the path doesn't map to a key-path (and $create is FALSE).
|
||||
*/
|
||||
protected function &uri_to_session_key($uri, $create = TRUE) {
|
||||
// Since our uri_to_session_key() method returns a reference, we
|
||||
// have to set up a failure flag variable.
|
||||
$fail = FALSE;
|
||||
$path = $this->getLocalPath($uri);
|
||||
$path_components = explode('/', $path);
|
||||
// Set up a reference to the root session:// 'directory.'
|
||||
$var = &$_SESSION['file_example'];
|
||||
// Handle case of just session://.
|
||||
if (count($path_components) < 1) {
|
||||
return $var;
|
||||
}
|
||||
// Walk through the path components and create keys in $_SESSION,
|
||||
// unless we're told not to create them.
|
||||
foreach ($path_components as $component) {
|
||||
if ($create || isset($var[$component])) {
|
||||
$var = &$var[$component];
|
||||
}
|
||||
else {
|
||||
// This path doesn't exist as keys, either because the
|
||||
// key doesn't exist, or because we're told not to create it.
|
||||
return $fail;
|
||||
}
|
||||
}
|
||||
return $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for flock().
|
||||
*
|
||||
* The $_SESSION variable has no locking capability, so return TRUE.
|
||||
*
|
||||
* @param int $operation
|
||||
* One of the following:
|
||||
* - LOCK_SH to acquire a shared lock (reader).
|
||||
* - LOCK_EX to acquire an exclusive lock (writer).
|
||||
* - LOCK_UN to release a lock (shared or exclusive).
|
||||
* - LOCK_NB if you don't want flock() to block while locking (not
|
||||
* supported on Windows).
|
||||
*
|
||||
* @return bool
|
||||
* Always returns TRUE at the present time. (no support)
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-lock.php
|
||||
*/
|
||||
public function stream_lock($operation) {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for fread(), file_get_contents() etc.
|
||||
*
|
||||
* @param int $count
|
||||
* Maximum number of bytes to be read.
|
||||
*
|
||||
* @return string
|
||||
* The string that was read, or FALSE in case of an error.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-read.php
|
||||
*/
|
||||
public function stream_read($count) {
|
||||
if (is_string($this->sessionContent)) {
|
||||
$remaining_chars = drupal_strlen($this->sessionContent) - $this->streamPointer;
|
||||
$number_to_read = min($count, $remaining_chars);
|
||||
if ($remaining_chars > 0) {
|
||||
$buffer = drupal_substr($this->sessionContent, $this->streamPointer, $number_to_read);
|
||||
$this->streamPointer += $number_to_read;
|
||||
return $buffer;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for fwrite(), file_put_contents() etc.
|
||||
*
|
||||
* @param string $data
|
||||
* The string to be written.
|
||||
*
|
||||
* @return int
|
||||
* The number of bytes written (integer).
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-write.php
|
||||
*/
|
||||
public function stream_write($data) {
|
||||
// Sanitize the data in a simple way since we're putting it into the
|
||||
// session variable.
|
||||
$data = check_plain($data);
|
||||
$this->sessionContent = substr_replace($this->sessionContent, $data, $this->streamPointer);
|
||||
$this->streamPointer += drupal_strlen($data);
|
||||
return drupal_strlen($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for feof().
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if end-of-file has been reached.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-eof.php
|
||||
*/
|
||||
public function stream_eof() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for fseek().
|
||||
*
|
||||
* @param int $offset
|
||||
* The byte offset to got to.
|
||||
* @param int $whence
|
||||
* SEEK_SET, SEEK_CUR, or SEEK_END.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE on success.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-seek.php
|
||||
*/
|
||||
public function stream_seek($offset, $whence) {
|
||||
if (drupal_strlen($this->sessionContent) >= $offset) {
|
||||
$this->streamPointer = $offset;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for fflush().
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if data was successfully stored (or there was no data to store).
|
||||
* This always returns TRUE, as this example provides and needs no
|
||||
* flush support.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-flush.php
|
||||
*/
|
||||
public function stream_flush() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for ftell().
|
||||
*
|
||||
* @return int
|
||||
* The current offset in bytes from the beginning of file.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-tell.php
|
||||
*/
|
||||
public function stream_tell() {
|
||||
return $this->streamPointer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for fstat().
|
||||
*
|
||||
* @return array
|
||||
* An array with file status, or FALSE in case of an error - see fstat()
|
||||
* for a description of this array.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-stat.php
|
||||
*/
|
||||
public function stream_stat() {
|
||||
return array(
|
||||
'size' => drupal_strlen($this->sessionContent),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for fclose().
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if stream was successfully closed.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.stream-close.php
|
||||
*/
|
||||
public function stream_close() {
|
||||
$this->streamPointer = 0;
|
||||
// Unassign the reference.
|
||||
unset($this->sessionContent);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for unlink().
|
||||
*
|
||||
* @param string $uri
|
||||
* A string containing the uri to the resource to delete.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if resource was successfully deleted.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.unlink.php
|
||||
*/
|
||||
public function unlink($uri) {
|
||||
$path = $this->getLocalPath($uri);
|
||||
$path_components = preg_split('/\//', $path);
|
||||
$unset = '$_SESSION[\'file_example\']';
|
||||
foreach ($path_components as $component) {
|
||||
$unset .= '[\'' . $component . '\']';
|
||||
}
|
||||
// TODO: Is there a better way to delete from an array?
|
||||
// drupal_array_get_nested_value() doesn't work because it only returns
|
||||
// a reference; unsetting a reference only unsets the reference.
|
||||
eval("unset($unset);");
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for rename().
|
||||
*
|
||||
* @param string $from_uri
|
||||
* The uri to the file to rename.
|
||||
* @param string $to_uri
|
||||
* The new uri for file.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if file was successfully renamed.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.rename.php
|
||||
*/
|
||||
public function rename($from_uri, $to_uri) {
|
||||
$from_key = &$this->uri_to_session_key($from_uri);
|
||||
$to_key = &$this->uri_to_session_key($to_uri);
|
||||
if (is_dir($to_key) || is_file($to_key)) {
|
||||
return FALSE;
|
||||
}
|
||||
$to_key = $from_key;
|
||||
unset($from_key);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the directory from a given path.
|
||||
*
|
||||
* @param string $uri
|
||||
* A URI.
|
||||
*
|
||||
* @return string
|
||||
* A string containing the directory name.
|
||||
*
|
||||
* @see drupal_dirname()
|
||||
*/
|
||||
public function dirname($uri = NULL) {
|
||||
list($scheme, $target) = explode('://', $uri, 2);
|
||||
$target = $this->getTarget($uri);
|
||||
if (strpos($target, '/')) {
|
||||
$dirname = preg_replace('@/[^/]*$@', '', $target);
|
||||
}
|
||||
else {
|
||||
$dirname = '';
|
||||
}
|
||||
return $scheme . '://' . $dirname;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for mkdir().
|
||||
*
|
||||
* @param string $uri
|
||||
* A string containing the URI to the directory to create.
|
||||
* @param int $mode
|
||||
* Permission flags - see mkdir().
|
||||
* @param int $options
|
||||
* A bit mask of STREAM_REPORT_ERRORS and STREAM_MKDIR_RECURSIVE.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if directory was successfully created.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.mkdir.php
|
||||
*/
|
||||
public function mkdir($uri, $mode, $options) {
|
||||
// If this already exists, then we can't mkdir.
|
||||
if (is_dir($uri) || is_file($uri)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Create the key in $_SESSION;
|
||||
$this->uri_to_session_key($uri, TRUE);
|
||||
|
||||
// Place a magic file inside it to differentiate this from an empty file.
|
||||
$marker_uri = $uri . '/.isadir.txt';
|
||||
$this->uri_to_session_key($marker_uri, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for rmdir().
|
||||
*
|
||||
* @param string $uri
|
||||
* A string containing the URI to the directory to delete.
|
||||
* @param int $options
|
||||
* A bit mask of STREAM_REPORT_ERRORS.
|
||||
*
|
||||
* @return bool
|
||||
* TRUE if directory was successfully removed.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.rmdir.php
|
||||
*/
|
||||
public function rmdir($uri, $options) {
|
||||
$path = $this->getLocalPath($uri);
|
||||
$path_components = preg_split('/\//', $path);
|
||||
$unset = '$_SESSION[\'file_example\']';
|
||||
foreach ($path_components as $component) {
|
||||
$unset .= '[\'' . $component . '\']';
|
||||
}
|
||||
// TODO: I really don't like this eval.
|
||||
debug($unset, 'array element to be unset');
|
||||
eval("unset($unset);");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for stat().
|
||||
*
|
||||
* This important function goes back to the Unix way of doing things.
|
||||
* In this example almost the entire stat array is irrelevant, but the
|
||||
* mode is very important. It tells PHP whether we have a file or a
|
||||
* directory and what the permissions are. All that is packed up in a
|
||||
* bitmask. This is not normal PHP fodder.
|
||||
*
|
||||
* @param string $uri
|
||||
* A string containing the URI to get information about.
|
||||
* @param int $flags
|
||||
* A bit mask of STREAM_URL_STAT_LINK and STREAM_URL_STAT_QUIET.
|
||||
*
|
||||
* @return array|bool
|
||||
* An array with file status, or FALSE in case of an error - see fstat()
|
||||
* for a description of this array.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.url-stat.php
|
||||
*/
|
||||
public function url_stat($uri, $flags) {
|
||||
// Get a reference to the $_SESSION key for this URI.
|
||||
$key = $this->uri_to_session_key($uri, FALSE);
|
||||
// Default to fail.
|
||||
$return = FALSE;
|
||||
$mode = 0;
|
||||
|
||||
// We will call an array a directory and the root is always an array.
|
||||
if (is_array($key) && array_key_exists('.isadir.txt', $key)) {
|
||||
// S_IFDIR means it's a directory.
|
||||
$mode = 0040000;
|
||||
}
|
||||
elseif ($key !== FALSE) {
|
||||
// S_IFREG, means it's a file.
|
||||
$mode = 0100000;
|
||||
}
|
||||
|
||||
if ($mode) {
|
||||
$size = 0;
|
||||
if ($mode == 0100000) {
|
||||
$size = drupal_strlen($key);
|
||||
}
|
||||
|
||||
// There are no protections on this, so all writable.
|
||||
$mode |= 0777;
|
||||
$return = array(
|
||||
'dev' => 0,
|
||||
'ino' => 0,
|
||||
'mode' => $mode,
|
||||
'nlink' => 0,
|
||||
'uid' => 0,
|
||||
'gid' => 0,
|
||||
'rdev' => 0,
|
||||
'size' => $size,
|
||||
'atime' => 0,
|
||||
'mtime' => 0,
|
||||
'ctime' => 0,
|
||||
'blksize' => 0,
|
||||
'blocks' => 0,
|
||||
);
|
||||
}
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for opendir().
|
||||
*
|
||||
* @param string $uri
|
||||
* A string containing the URI to the directory to open.
|
||||
* @param int $options
|
||||
* Whether or not to enforce safe_mode (0x04).
|
||||
*
|
||||
* @return bool
|
||||
* TRUE on success.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.dir-opendir.php
|
||||
*/
|
||||
public function dir_opendir($uri, $options) {
|
||||
$var = &$this->uri_to_session_key($uri, FALSE);
|
||||
if ($var === FALSE || !array_key_exists('.isadir.txt', $var)) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// We grab the list of key names, flip it so that .isadir.txt can easily
|
||||
// be removed, then flip it back so we can easily walk it as a list.
|
||||
$this->directoryKeys = array_flip(array_keys($var));
|
||||
unset($this->directoryKeys['.isadir.txt']);
|
||||
$this->directoryKeys = array_keys($this->directoryKeys);
|
||||
$this->directoryPointer = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for readdir().
|
||||
*
|
||||
* @return string|bool
|
||||
* The next filename, or FALSE if there are no more files in the directory.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.dir-readdir.php
|
||||
*/
|
||||
public function dir_readdir() {
|
||||
if ($this->directoryPointer < count($this->directoryKeys)) {
|
||||
$next = $this->directoryKeys[$this->directoryPointer];
|
||||
$this->directoryPointer++;
|
||||
return $next;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for rewinddir().
|
||||
*
|
||||
* @return bool
|
||||
* TRUE on success.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.dir-rewinddir.php
|
||||
*/
|
||||
public function dir_rewinddir() {
|
||||
$this->directoryPointer = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for closedir().
|
||||
*
|
||||
* @return bool
|
||||
* TRUE on success.
|
||||
*
|
||||
* @see http://php.net/manual/en/streamwrapper.dir-closedir.php
|
||||
*/
|
||||
public function dir_closedir() {
|
||||
$this->directoryPointer = 0;
|
||||
unset($this->directoryKeys);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user