| 1 |
<?php
|
| 2 |
// $Id$
|
| 3 |
|
| 4 |
//////////////////////////////////////////////////////////////////////////////
|
| 5 |
// Module settings
|
| 6 |
|
| 7 |
define('BITCACHE_LINK', 'http://bitcache.org/');
|
| 8 |
define('BITCACHE_ROOT', variable_get('bitcache_root', file_directory_path() . '/bitcache'));
|
| 9 |
define('BITCACHE_BASE', 'bitcache');
|
| 10 |
define('BITCACHE_ALIAS', drupal_get_path_alias(BITCACHE_BASE));
|
| 11 |
define('BITCACHE_CRON', trim(variable_get('bitcache_cron', '')));
|
| 12 |
|
| 13 |
define('BITCACHE_SERVER', variable_get('bitcache_server', TRUE));
|
| 14 |
define('BITCACHE_TRANSFER_METHOD', variable_get('bitcache_transfer_method', 'read4k'));
|
| 15 |
define('BITCACHE_URL', url(BITCACHE_ALIAS . '/', array('absolute' => TRUE, 'prefix' => '', 'language' => (object)array('language' => ''))));
|
| 16 |
define('BITCACHE_DEPTH', variable_get('bitcache_depth', 0));
|
| 17 |
define('BITCACHE_WIDTH', variable_get('bitcache_width', 0));
|
| 18 |
|
| 19 |
define('BITCACHE_EXEC', variable_get('bitcache_exec', drupal_get_path('module', 'bitcache') . '/tools/bin/bit'));
|
| 20 |
define('BITCACHE_TABLE_DEFAULT', 'bitcache_data');
|
| 21 |
define('BITCACHE_TABLE_PREFIX', 'bitcache_data_');
|
| 22 |
|
| 23 |
//////////////////////////////////////////////////////////////////////////////
|
| 24 |
// Core API hooks
|
| 25 |
|
| 26 |
/**
|
| 27 |
* Implementation of hook_perm().
|
| 28 |
*/
|
| 29 |
function bitcache_help($path) {
|
| 30 |
switch ($path) {
|
| 31 |
case 'admin/help#bitcache':
|
| 32 |
return '<p>'. t('<a href="@bitcache" target="_blank">Bitcache</a> is a distributed <a href="http://en.wikipedia.org/wiki/Content-addressable_storage" target="_blank">content-addressable storage</a> (CAS) system. It provides repository storage for bitstreams (colloquially known as <a href="http://en.wikipedia.org/wiki/Binary_large_object" target="_blank">blobs</a>) of any length, each uniquely identified and addressed by a digital fingerprint derived through a secure <a href="http://en.wikipedia.org/wiki/Cryptographic_hash_function" target="_blank">cryptographic hash algorithm</a>.', array('@bitcache' => BITCACHE_LINK)) .'</p>'.
|
| 33 |
'<p>'. t('This module provides a Bitcache-compatible data storage repository for Drupal and implements the Bitcache <a href="http://en.wikipedia.org/wiki/Representational_State_Transfer" target="_blank" title="Representational State Transfer">REST</a> <acronym title="Application Programming Interface">API</acronym> for interoperability with the standalone Bitcache command-line and synchronization tools.') .'</p>'.
|
| 34 |
'<p>'. t('For more information please refer to the <a href="@project">drupal.org project page</a>.', array('@project' => 'http://drupal.org/project/bitcache')) .'</p>';
|
| 35 |
case 'admin/settings/bitcache':
|
| 36 |
return '<p>'. t('<a href="@bitcache" target="_blank">Bitcache</a> provides a distributed, content-addressable repository for data storage.', array('@bitcache' => BITCACHE_LINK)) .'</p>';
|
| 37 |
case 'admin/settings/bitcache/repositories':
|
| 38 |
return '<p>'. t('Below is a list of all configured Bitcache repositories available to this Drupal site.') .'</p>';
|
| 39 |
}
|
| 40 |
}
|
| 41 |
|
| 42 |
/**
|
| 43 |
* Implementation of hook_perm().
|
| 44 |
*/
|
| 45 |
function bitcache_perm() {
|
| 46 |
return array(
|
| 47 |
'administer bitcache',
|
| 48 |
'list bitstreams',
|
| 49 |
'access bitstreams',
|
| 50 |
'upload bitstreams',
|
| 51 |
'delete bitstreams',
|
| 52 |
);
|
| 53 |
}
|
| 54 |
|
| 55 |
/**
|
| 56 |
* Implementation of hook_menu().
|
| 57 |
*/
|
| 58 |
function bitcache_menu() {
|
| 59 |
return array(
|
| 60 |
// Bitcache HTTP API endpoint
|
| 61 |
BITCACHE_BASE => array(
|
| 62 |
'title' => 'Bitcache API',
|
| 63 |
'type' => MENU_CALLBACK,
|
| 64 |
'access arguments' => array('list bitstreams'),
|
| 65 |
'page callback' => 'bitcache_server',
|
| 66 |
'file' => 'bitcache.server.inc',
|
| 67 |
),
|
| 68 |
BITCACHE_ALIAS . '/%' => array(
|
| 69 |
'type' => MENU_CALLBACK,
|
| 70 |
'access arguments' => array('access bitstreams'),
|
| 71 |
'page callback' => 'bitcache_server',
|
| 72 |
'page arguments' => array(1),
|
| 73 |
'file' => 'bitcache.server.inc',
|
| 74 |
),
|
| 75 |
|
| 76 |
// Administer >> Content management >> Bitstreams
|
| 77 |
'admin/content/bitcache' => array(
|
| 78 |
'title' => 'Bitstreams',
|
| 79 |
'description' => 'Manage Bitcache data.',
|
| 80 |
'access arguments' => array('administer bitcache'),
|
| 81 |
'page callback' => 'drupal_get_form',
|
| 82 |
'page arguments' => array('bitcache_admin_bitstreams'),
|
| 83 |
'file' => 'bitcache.admin.inc',
|
| 84 |
),
|
| 85 |
'admin/content/bitcache/list' => array(
|
| 86 |
'title' => 'List',
|
| 87 |
'type' => MENU_DEFAULT_LOCAL_TASK,
|
| 88 |
'weight' => -10,
|
| 89 |
),
|
| 90 |
'admin/content/bitcache/upload' => array(
|
| 91 |
'title' => 'Upload bitstream',
|
| 92 |
'type' => MENU_LOCAL_TASK,
|
| 93 |
'access arguments' => array('administer bitcache'),
|
| 94 |
'page callback' => 'drupal_get_form',
|
| 95 |
'page arguments' => array('bitcache_admin_bitstream_upload'),
|
| 96 |
'file' => 'bitcache.admin.inc',
|
| 97 |
'weight' => 10,
|
| 98 |
),
|
| 99 |
'admin/content/bitcache/fetch' => array(
|
| 100 |
'title' => 'Fetch bitstream from URL',
|
| 101 |
'type' => MENU_LOCAL_TASK,
|
| 102 |
'access arguments' => array('administer bitcache'),
|
| 103 |
'page callback' => 'drupal_get_form',
|
| 104 |
'page arguments' => array('bitcache_admin_bitstream_fetch'),
|
| 105 |
'file' => 'bitcache.admin.inc',
|
| 106 |
'weight' => 20,
|
| 107 |
),
|
| 108 |
'admin/content/bitcache/view/%' => array(
|
| 109 |
'title' => 'View bitstream',
|
| 110 |
'type' => MENU_CALLBACK,
|
| 111 |
'access arguments' => array('administer bitcache'),
|
| 112 |
'page callback' => 'bitcache_admin_bitstream_view',
|
| 113 |
'page arguments' => array(4),
|
| 114 |
'file' => 'bitcache.admin.inc',
|
| 115 |
),
|
| 116 |
'admin/content/bitcache/delete/%' => array(
|
| 117 |
'title' => 'Delete bitstream',
|
| 118 |
'type' => MENU_CALLBACK,
|
| 119 |
'access arguments' => array('administer bitcache'),
|
| 120 |
'page callback' => 'drupal_get_form',
|
| 121 |
'page arguments' => array('bitcache_admin_bitstream_delete', 4),
|
| 122 |
'file' => 'bitcache.admin.inc',
|
| 123 |
),
|
| 124 |
|
| 125 |
// Administer >> Site configuration >> Data storage
|
| 126 |
'admin/settings/bitcache' => array(
|
| 127 |
'title' => 'Data storage',
|
| 128 |
'description' => 'Settings for Bitcache.',
|
| 129 |
'access arguments' => array('administer bitcache'),
|
| 130 |
'page callback' => 'drupal_get_form',
|
| 131 |
'page arguments' => array('bitcache_admin_settings'),
|
| 132 |
'file' => 'bitcache.admin.inc',
|
| 133 |
),
|
| 134 |
'admin/settings/bitcache/config' => array(
|
| 135 |
'title' => 'Settings',
|
| 136 |
'type' => MENU_DEFAULT_LOCAL_TASK,
|
| 137 |
'weight' => -10,
|
| 138 |
),
|
| 139 |
'admin/settings/bitcache/repositories' => array(
|
| 140 |
'title' => 'Repositories',
|
| 141 |
'type' => MENU_LOCAL_TASK,
|
| 142 |
'access arguments' => array('administer bitcache'),
|
| 143 |
'page callback' => 'drupal_get_form',
|
| 144 |
'page arguments' => array('bitcache_admin_repos'),
|
| 145 |
'file' => 'bitcache.admin.inc',
|
| 146 |
),
|
| 147 |
'admin/settings/bitcache/repository/add' => array(
|
| 148 |
'title' => 'Add repository',
|
| 149 |
'type' => MENU_LOCAL_TASK,
|
| 150 |
'parent' => 'admin/settings/bitcache',
|
| 151 |
'weight' => 1,
|
| 152 |
'access arguments' => array('administer bitcache'),
|
| 153 |
'page callback' => 'bitcache_admin_repo_create',
|
| 154 |
'file' => 'bitcache.admin.inc',
|
| 155 |
),
|
| 156 |
'admin/settings/bitcache/repository/edit' => array(
|
| 157 |
'title' => 'Configure repository',
|
| 158 |
'type' => MENU_CALLBACK,
|
| 159 |
'access arguments' => array('administer bitcache'),
|
| 160 |
'page callback' => 'bitcache_admin_repo_edit',
|
| 161 |
'file' => 'bitcache.admin.inc',
|
| 162 |
),
|
| 163 |
'admin/settings/bitcache/repository/delete' => array(
|
| 164 |
'title' => 'Delete repository',
|
| 165 |
'type' => MENU_CALLBACK,
|
| 166 |
'access arguments' => array('administer bitcache'),
|
| 167 |
'page callback' => 'drupal_get_form',
|
| 168 |
'page arguments' => array('bitcache_admin_repo_delete'),
|
| 169 |
'file' => 'bitcache.admin.inc',
|
| 170 |
),
|
| 171 |
);
|
| 172 |
}
|
| 173 |
|
| 174 |
/**
|
| 175 |
* Implementation of hook_init().
|
| 176 |
*/
|
| 177 |
function bitcache_init() {
|
| 178 |
foreach (array('token', 'services'/*, 'rules'*/) as $module) {
|
| 179 |
if (module_exists($module)) {
|
| 180 |
module_load_include('inc', 'bitcache', 'bitcache.' . $module);
|
| 181 |
}
|
| 182 |
}
|
| 183 |
}
|
| 184 |
|
| 185 |
/**
|
| 186 |
* Implementation of hook_form_alter().
|
| 187 |
*/
|
| 188 |
function bitcache_form_alter(&$form, $form_state, $form_id) {
|
| 189 |
switch ($form_id) {
|
| 190 |
case 'globalredirect_settings':
|
| 191 |
// Display a prominent warning on the Global Redirect settings page if
|
| 192 |
// the 'Deslash' option has been enabled:
|
| 193 |
if (module_exists('globalredirect')) {
|
| 194 |
if (BITCACHE_SERVER && variable_get('globalredirect_deslash', GLOBALREDIRECT_DESLASH_ENABLED) == GLOBALREDIRECT_DESLASH_ENABLED) {
|
| 195 |
drupal_set_message(t('Warning: the Global Redirect deslash setting is incompatible with the Bitcache REST API.'), 'warning');
|
| 196 |
}
|
| 197 |
}
|
| 198 |
break;
|
| 199 |
}
|
| 200 |
}
|
| 201 |
|
| 202 |
/**
|
| 203 |
* Implementation of hook_theme().
|
| 204 |
*/
|
| 205 |
function bitcache_theme() {
|
| 206 |
return array(
|
| 207 |
'bitcache_admin_bitstreams' => array(
|
| 208 |
'arguments' => array('form' => NULL),
|
| 209 |
'file' => 'bitcache.admin.inc',
|
| 210 |
),
|
| 211 |
'bitcache_admin_settings' => array(
|
| 212 |
'arguments' => array('form' => NULL),
|
| 213 |
'file' => 'bitcache.admin.inc',
|
| 214 |
),
|
| 215 |
'bitcache_admin_repos' => array(
|
| 216 |
'arguments' => array('form' => NULL),
|
| 217 |
'file' => 'bitcache.admin.inc',
|
| 218 |
),
|
| 219 |
);
|
| 220 |
}
|
| 221 |
|
| 222 |
/**
|
| 223 |
* Implementation of hook_hook_info().
|
| 224 |
*/
|
| 225 |
function bitcache_hook_info() {
|
| 226 |
return array(
|
| 227 |
'bitcache' => array(
|
| 228 |
'bitcache' => array(
|
| 229 |
'insert' => array(
|
| 230 |
'runs when' => t('After uploading a new bitstream'),
|
| 231 |
),
|
| 232 |
'delete' => array(
|
| 233 |
'runs when' => t('After deleting an existing bitstream'),
|
| 234 |
),
|
| 235 |
),
|
| 236 |
),
|
| 237 |
);
|
| 238 |
}
|
| 239 |
|
| 240 |
/**
|
| 241 |
* Implementation of hook_action_info().
|
| 242 |
*/
|
| 243 |
function bitcache_action_info() {
|
| 244 |
return array(
|
| 245 |
'bitcache_cron_action' => array(
|
| 246 |
'description' => t('Execute cron script'),
|
| 247 |
'type' => 'bitcache',
|
| 248 |
'configurable' => FALSE,
|
| 249 |
'hooks' => array(
|
| 250 |
'bitcache' => array('insert', 'delete'),
|
| 251 |
),
|
| 252 |
),
|
| 253 |
'bitcache_sync_action' => array(
|
| 254 |
'description' => t('Synchronize with Bitcache server'),
|
| 255 |
'type' => 'bitcache',
|
| 256 |
'configurable' => TRUE,
|
| 257 |
'hooks' => array(
|
| 258 |
'bitcache' => array('insert', 'delete'),
|
| 259 |
)
|
| 260 |
)
|
| 261 |
);
|
| 262 |
}
|
| 263 |
|
| 264 |
function bitcache_sync_action_form($context) {
|
| 265 |
$form = array();
|
| 266 |
/*$form['url'] = array(
|
| 267 |
'#type' => 'textfield',
|
| 268 |
'#title' => t('URL'),
|
| 269 |
'#description' => t('The URL of the Bitcache server.'),
|
| 270 |
'#default_value' => isset($context['url']) ? $context['url'] : '',
|
| 271 |
'#required' => TRUE,
|
| 272 |
);*/
|
| 273 |
/*$form['mode'] = array(
|
| 274 |
'#type' => 'checkboxes',
|
| 275 |
'#title' => t('Direction'),
|
| 276 |
'#default_value' => !empty($context['mode']) ? $context['mode'] : array(),
|
| 277 |
'#options' => array('push' => t('Push'), 'pull' => t('Pull')),
|
| 278 |
'#description' => t('Which direction the synchronization should be performed in.'),
|
| 279 |
'#required' => TRUE,
|
| 280 |
);*/
|
| 281 |
// TODO
|
| 282 |
return $form;
|
| 283 |
}
|
| 284 |
|
| 285 |
function bitcache_sync_action_submit($form, &$form_state) {
|
| 286 |
return array(
|
| 287 |
'url' => $form_state['values']['url'],
|
| 288 |
);
|
| 289 |
}
|
| 290 |
|
| 291 |
function bitcache_sync_action(&$object, array $context = array()) {
|
| 292 |
//$context['url']
|
| 293 |
}
|
| 294 |
|
| 295 |
/**
|
| 296 |
* Implementation of hook_cron().
|
| 297 |
*/
|
| 298 |
function bitcache_cron() {
|
| 299 |
if (strlen(BITCACHE_CRON) > 0) {
|
| 300 |
exec(BITCACHE_CRON .' 2>&1', $output, $retval);
|
| 301 |
if ($retval == 0) {
|
| 302 |
watchdog('bitcache', 'Cron script completed.');
|
| 303 |
}
|
| 304 |
else {
|
| 305 |
watchdog('bitcache', 'Cron script failed with return value %retval and output: %output', array('%retval' => $retval, '%output' => implode("\n", $output)), WATCHDOG_ERROR, l('configure', 'admin/settings/bitcache'));
|
| 306 |
}
|
| 307 |
}
|
| 308 |
}
|
| 309 |
|
| 310 |
function bitcache_cron_action(&$object, array $context = array()) {
|
| 311 |
bitcache_cron();
|
| 312 |
}
|
| 313 |
|
| 314 |
//////////////////////////////////////////////////////////////////////////////
|
| 315 |
// Bitcache API hooks
|
| 316 |
|
| 317 |
/**
|
| 318 |
* Implementation of hook_bitcache().
|
| 319 |
*/
|
| 320 |
function bitcache_bitcache($op, $id, &$stream = NULL) {
|
| 321 |
static $ops = array('insert', 'delete');
|
| 322 |
if (!in_array($op, $ops)) {
|
| 323 |
return;
|
| 324 |
}
|
| 325 |
|
| 326 |
if (module_exists('rules')) {
|
| 327 |
rules_invoke_event('bitcache_' . $op, array('stream' => &$stream));
|
| 328 |
}
|
| 329 |
|
| 330 |
if (module_exists('trigger')) {
|
| 331 |
$object = (object)array('id' => $id);
|
| 332 |
$context = array('hook' => 'bitcache', 'op' => $op, 'stream' => &$stream);
|
| 333 |
foreach (_trigger_get_hook_aids('bitcache', $op) as $aid => $action_info) {
|
| 334 |
if ($action_info['type'] == 'bitcache') {
|
| 335 |
actions_do($aid, $object, $context); // trigger action
|
| 336 |
}
|
| 337 |
}
|
| 338 |
}
|
| 339 |
}
|
| 340 |
|
| 341 |
/**
|
| 342 |
* Implementation of hook_bitcache_adapters().
|
| 343 |
*/
|
| 344 |
function bitcache_bitcache_adapters() {
|
| 345 |
return array(
|
| 346 |
'sql' => array(
|
| 347 |
'title' => t('Database'),
|
| 348 |
'description' => t('Stores data in a Drupal database table.'),
|
| 349 |
'enabled' => TRUE,
|
| 350 |
'file' => drupal_get_path('module', 'bitcache') . '/adapters/sql.inc',
|
| 351 |
'class' => 'Bitcache_SQLRepository',
|
| 352 |
),
|
| 353 |
'pdo' => array(
|
| 354 |
'title' => t('Database (PDO)'),
|
| 355 |
'description' => t('Stores data in a <a href="http://php.net/manual/en/book.pdo.php" target="_blank">PHP Data Objects (PDO)</a> database.'),
|
| 356 |
'enabled' => extension_loaded('pdo'),
|
| 357 |
'file' => drupal_get_path('module', 'bitcache') . '/adapters/pdo.inc',
|
| 358 |
'class' => 'Bitcache_PDORepository',
|
| 359 |
),
|
| 360 |
'gdbm' => array(
|
| 361 |
'title' => t('Database (GDBM)'),
|
| 362 |
'description' => t('Stores data in a <a href="http://www.vivtek.com/gdbm/" target="_blank">GDBM</a> database.'),
|
| 363 |
'enabled' => extension_loaded('dba') && in_array('gdbm', dba_handlers()),
|
| 364 |
'file' => drupal_get_path('module', 'bitcache') . '/adapters/dba.inc',
|
| 365 |
'class' => 'Bitcache_DBARepository',
|
| 366 |
),
|
| 367 |
'file' => array(
|
| 368 |
'title' => t('File system'),
|
| 369 |
'description' => t('Stores data in a file system directory.'),
|
| 370 |
'enabled' => TRUE,
|
| 371 |
'file' => drupal_get_path('module', 'bitcache') . '/adapters/file.inc',
|
| 372 |
'class' => 'Bitcache_FileRepository',
|
| 373 |
),
|
| 374 |
'aws_s3' => array(
|
| 375 |
'title' => t('Amazon S3'),
|
| 376 |
'description' => t('Stores data in an <a href="https://s3.amazonaws.com/">Amazon Simple Storage Service (S3)</a> bucket.'),
|
| 377 |
'enabled' => file_exists(drupal_get_path('module', 'bitcache') . '/vendor/tarzan/tarzan.class.php'),
|
| 378 |
'file' => drupal_get_path('module', 'bitcache') . '/adapters/aws-s3.inc',
|
| 379 |
'class' => 'Bitcache_S3Repository',
|
| 380 |
),
|
| 381 |
);
|
| 382 |
}
|
| 383 |
|
| 384 |
/**
|
| 385 |
* Implementation of hook_bitcache_algorithms().
|
| 386 |
*/
|
| 387 |
function bitcache_bitcache_algorithms($op) {
|
| 388 |
$available = $algorithms = array();
|
| 389 |
switch ($op) {
|
| 390 |
case 'fingerprint':
|
| 391 |
case 'hash':
|
| 392 |
$available = function_exists('hash_algos') ? hash_algos() : array('md5', 'sha1');
|
| 393 |
$algorithms = array(
|
| 394 |
'md5' => t('MD5 (128-bit)'),
|
| 395 |
'sha1' => t('SHA-1 (160-bit)'),
|
| 396 |
'sha256' => t('SHA-256 (256-bit)'),
|
| 397 |
'sha384' => t('SHA-384 (384-bit)'),
|
| 398 |
'sha512' => t('SHA-512 (512-bit)'),
|
| 399 |
);
|
| 400 |
break;
|
| 401 |
case 'encode':
|
| 402 |
case 'decode':
|
| 403 |
$algorithms = array(
|
| 404 |
'base16' => t('Base 16 (0-9, a-f; hexadecimal)'),
|
| 405 |
//'base32' => t('Base 32 (A-Z, 2-7; RFC 4648)'),
|
| 406 |
'base36' => t('Base 36 (0-9, a-z)'),
|
| 407 |
'base62' => t('Base 62 (0-9, A-Z, a-z)'),
|
| 408 |
);
|
| 409 |
$available = array_keys($algorithms);
|
| 410 |
break;
|
| 411 |
case 'encrypt':
|
| 412 |
case 'decrypt':
|
| 413 |
$available = function_exists('mcrypt_list_algorithms') ? mcrypt_list_algorithms() : array();
|
| 414 |
$algorithms = array(
|
| 415 |
'rijndael-128' => t('AES-128'),
|
| 416 |
'rijndael-192' => t('AES-192'),
|
| 417 |
'rijndael-256' => t('AES-256'),
|
| 418 |
);
|
| 419 |
break;
|
| 420 |
case 'compress':
|
| 421 |
case 'decompress':
|
| 422 |
if (function_exists('gzencode')) {
|
| 423 |
$available[] = 'gzip';
|
| 424 |
}
|
| 425 |
if (function_exists('bzcompress')) {
|
| 426 |
$available[] = 'bzip2';
|
| 427 |
}
|
| 428 |
$algorithms = array(
|
| 429 |
'gzip' => t('gzip'),
|
| 430 |
'bzip2' => t('bzip2'),
|
| 431 |
);
|
| 432 |
break;
|
| 433 |
}
|
| 434 |
return array_intersect_key($algorithms, array_flip($available));
|
| 435 |
}
|
| 436 |
|
| 437 |
//////////////////////////////////////////////////////////////////////////////
|
| 438 |
// Bitcache repository API
|
| 439 |
|
| 440 |
/**
|
| 441 |
* Returns information on available cryptographic algorithms.
|
| 442 |
*/
|
| 443 |
function bitcache_get_algorithms($op) {
|
| 444 |
return module_invoke_all('bitcache_algorithms', $op);
|
| 445 |
}
|
| 446 |
|
| 447 |
/**
|
| 448 |
* Returns information about modules that implement hook_bitcache().
|
| 449 |
*/
|
| 450 |
function bitcache_get_modules($op = NULL) {
|
| 451 |
switch ($op) {
|
| 452 |
case 'info':
|
| 453 |
$modules = bitcache_get_modules('names');
|
| 454 |
if (!empty($modules)) {
|
| 455 |
$result = db_query("SELECT name, info FROM {system} WHERE type = 'module' AND name IN (" . db_placeholders($modules, 'varchar') . ") ORDER BY weight ASC", $modules);
|
| 456 |
while ($row = db_fetch_object($result)) {
|
| 457 |
$info = (object)unserialize($row->info);
|
| 458 |
$info->title = $info->name;
|
| 459 |
$info->name = $row->name;
|
| 460 |
$modules[$row->name] = $info;
|
| 461 |
}
|
| 462 |
}
|
| 463 |
return $modules;
|
| 464 |
case 'titles':
|
| 465 |
$modules = bitcache_get_modules('info');
|
| 466 |
foreach ($modules as $name => $info) {
|
| 467 |
$modules[$name] = $info->title;
|
| 468 |
}
|
| 469 |
return $modules;
|
| 470 |
case 'names':
|
| 471 |
default:
|
| 472 |
$modules = module_implements('bitcache');
|
| 473 |
$modules = empty($modules) ? $modules : array_combine($modules, $modules);
|
| 474 |
unset($modules['bitcache']); // ignore self
|
| 475 |
return $modules;
|
| 476 |
}
|
| 477 |
}
|
| 478 |
|
| 479 |
/**
|
| 480 |
* Returns information on the supported and enabled REST API methods.
|
| 481 |
*/
|
| 482 |
function bitcache_get_features() {
|
| 483 |
static $default = array('index', 'get', 'post', 'put', 'delete');
|
| 484 |
return array_filter(variable_get('bitcache_features', array_combine($default, $default)), 'is_string');
|
| 485 |
}
|
| 486 |
|
| 487 |
/**
|
| 488 |
* Returns information on the available storage adapters (repository backends).
|
| 489 |
*/
|
| 490 |
function bitcache_get_adapters($op = NULL, $enabled_only = FALSE) {
|
| 491 |
static $adapters = array();
|
| 492 |
if (empty($adapters)) {
|
| 493 |
foreach (module_implements('bitcache_adapters') as $module) {
|
| 494 |
foreach (module_invoke($module, 'bitcache_adapters') as $name => $info) {
|
| 495 |
$info['name'] = $name;
|
| 496 |
$info['module'] = $module;
|
| 497 |
$info['enabled'] = isset($info['enabled']) ? (bool)$info['enabled'] : TRUE;
|
| 498 |
$adapters[$name] = (object)$info;
|
| 499 |
}
|
| 500 |
}
|
| 501 |
}
|
| 502 |
|
| 503 |
$result = array();
|
| 504 |
foreach ($adapters as $name => $info) {
|
| 505 |
if (!$enabled_only || !empty($info->enabled)) {
|
| 506 |
switch ($op) {
|
| 507 |
case 'titles':
|
| 508 |
$result[$name] = $info->title;
|
| 509 |
break;
|
| 510 |
default:
|
| 511 |
$result[$name] = $info;
|
| 512 |
break;
|
| 513 |
}
|
| 514 |
}
|
| 515 |
}
|
| 516 |
return $result;
|
| 517 |
}
|
| 518 |
|
| 519 |
/**
|
| 520 |
* Determines if a storage adapter is available.
|
| 521 |
*/
|
| 522 |
function bitcache_has_adapter($adapter) {
|
| 523 |
$adapters = bitcache_get_adapters();
|
| 524 |
return isset($adapters[$adapter]) && !empty($adapters[$adapter]->enabled);
|
| 525 |
}
|
| 526 |
|
| 527 |
/**
|
| 528 |
* Returns a storage adapter class.
|
| 529 |
*/
|
| 530 |
function bitcache_get_adapter_class($adapter, $load = TRUE) {
|
| 531 |
$adapters = bitcache_get_adapters();
|
| 532 |
if (isset($adapters[$adapter]) && ($adapter = $adapters[$adapter])) {
|
| 533 |
if ($load && isset($adapter->file) && ($file = './' . $adapter->file) && is_file($file)) {
|
| 534 |
require_once $file;
|
| 535 |
}
|
| 536 |
return $adapter->class;
|
| 537 |
}
|
| 538 |
}
|
| 539 |
|
| 540 |
/**
|
| 541 |
* Returns a list of database-backed repositories' table names.
|
| 542 |
*/
|
| 543 |
function bitcache_get_repository_tables($refresh = FALSE) {
|
| 544 |
static $tables;
|
| 545 |
if (!is_array($tables) || $refresh) {
|
| 546 |
$result = db_query("SELECT name FROM {bitcache_repositories} WHERE adapter = 'sql' AND name != 'bitcache' ORDER BY weight ASC, name ASC");
|
| 547 |
$tables = array('bitcache' => BITCACHE_TABLE_DEFAULT);
|
| 548 |
while ($row = db_fetch_object($result)) {
|
| 549 |
if (db_table_exists($table = BITCACHE_TABLE_PREFIX . $row->name)) {
|
| 550 |
$tables[$row->name] = $table;
|
| 551 |
}
|
| 552 |
}
|
| 553 |
}
|
| 554 |
return $tables;
|
| 555 |
}
|
| 556 |
|
| 557 |
/**
|
| 558 |
* Returns the Bitcache database schema for a given table.
|
| 559 |
*/
|
| 560 |
function bitcache_get_schema($table = BITCACHE_TABLE_DEFAULT, $rebuild = FALSE) {
|
| 561 |
if (!($schema = drupal_get_schema($table, $rebuild))) {
|
| 562 |
module_load_include('install', 'bitcache');
|
| 563 |
$schema = bitcache_schema();
|
| 564 |
$schema = isset($schema[$table]) ? $schema[$table] : array();
|
| 565 |
}
|
| 566 |
return $schema;
|
| 567 |
}
|
| 568 |
|
| 569 |
/**
|
| 570 |
* Returns information on the available Bitcache repositories.
|
| 571 |
*/
|
| 572 |
function bitcache_get_repositories($op = 'info') {
|
| 573 |
static $repos = array();
|
| 574 |
if (empty($repos)) {
|
| 575 |
$result = db_query("SELECT name FROM {bitcache_repositories} ORDER BY weight ASC, name ASC");
|
| 576 |
while ($row = db_fetch_object($result)) {
|
| 577 |
$repos[$row->name] = bitcache_get_repository($row->name);
|
| 578 |
}
|
| 579 |
}
|
| 580 |
|
| 581 |
$result = $repos;
|
| 582 |
switch ($op) {
|
| 583 |
case 'names':
|
| 584 |
case 'adapters':
|
| 585 |
case 'modules':
|
| 586 |
case 'titles':
|
| 587 |
case 'weights':
|
| 588 |
$property = substr($op, 0, -1);
|
| 589 |
foreach ($repos as $name => $repo) {
|
| 590 |
$result[$name] = $repo->options[$property];
|
| 591 |
}
|
| 592 |
break;
|
| 593 |
case 'options':
|
| 594 |
case 'settings':
|
| 595 |
case 'info':
|
| 596 |
foreach ($repos as $name => $repo) {
|
| 597 |
$result[$name] = $repo->options;
|
| 598 |
}
|
| 599 |
break;
|
| 600 |
case 'config':
|
| 601 |
//$repos[$name] = array('adapter' => 'file', 'path' => $settings['location'], 'enabled' => TRUE); // FIXME
|
| 602 |
break;
|
| 603 |
case 'api':
|
| 604 |
default:
|
| 605 |
break;
|
| 606 |
}
|
| 607 |
|
| 608 |
return $result;
|
| 609 |
}
|
| 610 |
|
| 611 |
/**
|
| 612 |
* Creates a new repository.
|
| 613 |
*/
|
| 614 |
function bitcache_create_repository($name, array $options = array()) {
|
| 615 |
$options = array_merge(array('title' => $name, 'description' => '', 'adapter' => 'sql'), (array)$options);
|
| 616 |
unset($options['name'], $options['options']); // just in case
|
| 617 |
|
| 618 |
if ($options['adapter'] == 'file') {
|
| 619 |
$options['location'] = !empty($options['location']) ? $options['location'] : BITCACHE_ROOT . '/' . $name;
|
| 620 |
@mkdir(bitcache_token_replace($options['location']), 0777, TRUE);
|
| 621 |
}
|
| 622 |
|
| 623 |
$record = array_intersect_key($options, array_flip(array('module', 'adapter', 'enabled', 'mutable', 'indexed', 'weight')));
|
| 624 |
$record = array_merge(array('name' => $name, 'module' => '', 'adapter' => 'sql', 'enabled' => TRUE, 'mutable' => TRUE, 'indexed' => FALSE, 'weight' => 0,
|
| 625 |
'options' => serialize(array_diff_key($options, $record))), $record);
|
| 626 |
$record = (object)$record;
|
| 627 |
|
| 628 |
return drupal_write_record('bitcache_repositories', $record) ? bitcache_get_repository($name) : FALSE;
|
| 629 |
}
|
| 630 |
|
| 631 |
/**
|
| 632 |
* Renames a repository.
|
| 633 |
*/
|
| 634 |
function bitcache_rename_repository($old_name, $new_name, array $options = array()) {
|
| 635 |
if (($repo = bitcache_get_repository($old_name))) {
|
| 636 |
if (db_query("UPDATE {bitcache_repositories} SET name = '%s' WHERE name = '%s'", $new_name, $old_name)) {
|
| 637 |
return is_callable(array($repo, 'rename')) ? $repo->rename($old_name, $new_name, $options) : TRUE;
|
| 638 |
}
|
| 639 |
return FALSE;
|
| 640 |
}
|
| 641 |
}
|
| 642 |
|
| 643 |
/**
|
| 644 |
* Updates options for a repository.
|
| 645 |
*/
|
| 646 |
function bitcache_update_repository($name, array $options = array()) {
|
| 647 |
if (($repo = bitcache_get_repository($name))) {
|
| 648 |
$options = array_diff_key($options, array_flip(array('name', 'module', 'adapter', 'enabled', 'mutable', 'indexed', 'weight', 'options')));
|
| 649 |
return db_query("UPDATE {bitcache_repositories} SET options = '%s' WHERE name = '%s'", serialize($options), $name);
|
| 650 |
}
|
| 651 |
}
|
| 652 |
|
| 653 |
/**
|
| 654 |
* Deletes a repository.
|
| 655 |
*/
|
| 656 |
function bitcache_delete_repository($name, array $options = array()) {
|
| 657 |
if (isset($GLOBALS['bitcache_repository']) && $GLOBALS['bitcache_repository'] == $name) {
|
| 658 |
unset($GLOBALS['bitcache_repository']);
|
| 659 |
}
|
| 660 |
|
| 661 |
if (($repo = bitcache_get_repository($name))) {
|
| 662 |
if (db_query("DELETE FROM {bitcache_repositories} WHERE name = '%s'", $name)) {
|
| 663 |
return is_callable(array($repo, 'destroy')) ? $repo->destroy($options) : TRUE;
|
| 664 |
}
|
| 665 |
return FALSE;
|
| 666 |
}
|
| 667 |
}
|
| 668 |
|
| 669 |
/**
|
| 670 |
* Returns a repository instance.
|
| 671 |
*/
|
| 672 |
function bitcache_get_repository($name = 'bitcache') {
|
| 673 |
module_load_include('inc', 'bitcache');
|
| 674 |
|
| 675 |
if (is_null($name)) { // create repository proxy
|
| 676 |
return new Bitcache_AggregateRepository(bitcache_get_repositories('api'));
|
| 677 |
}
|
| 678 |
|
| 679 |
$repo = db_fetch_array(db_query("SELECT * FROM {bitcache_repositories} WHERE name = '%s'", $name));
|
| 680 |
$repo = array_merge(unserialize($repo['options']), array_diff_key($repo, array('options' => NULL)));
|
| 681 |
$repo = ($name == 'bitcache') ? array_merge($repo, array('table' => BITCACHE_TABLE_DEFAULT)) : $repo;
|
| 682 |
|
| 683 |
$class = bitcache_has_adapter($repo['adapter']) ? bitcache_get_adapter_class(!empty($repo['adapter']) ? $repo['adapter'] : 'file') : NULL;
|
| 684 |
return $class && class_exists($class) ? new $class($repo) : (object)array('options' => $repo);
|
| 685 |
}
|
| 686 |
|
| 687 |
/**
|
| 688 |
* Returns the total number of bitstreams in a repository.
|
| 689 |
*/
|
| 690 |
function bitcache_get_repository_count($name = NULL) {
|
| 691 |
return count(bitcache_get_repository($name));
|
| 692 |
}
|
| 693 |
|
| 694 |
/**
|
| 695 |
* Returns the total byte size of a repository.
|
| 696 |
*/
|
| 697 |
function bitcache_get_repository_size($name = NULL) {
|
| 698 |
return ($repo = bitcache_get_repository($name)) ? $repo->size() : 0;
|
| 699 |
}
|
| 700 |
|
| 701 |
/**
|
| 702 |
* Limits future queries and operations to a particular repository.
|
| 703 |
*/
|
| 704 |
function bitcache_use_repository($name = NULL) {
|
| 705 |
if (is_null($name)) {
|
| 706 |
unset($GLOBALS['bitcache_repository']);
|
| 707 |
}
|
| 708 |
else {
|
| 709 |
$GLOBALS['bitcache_repository'] = $name;
|
| 710 |
}
|
| 711 |
}
|
| 712 |
|
| 713 |
//////////////////////////////////////////////////////////////////////////////
|
| 714 |
// Bitcache bitstream API
|
| 715 |
|
| 716 |
function bitcache_l($text, $id, array $options = array('absolute' => TRUE)) {
|
| 717 |
$options += array('prefix' => '', 'language' => array());
|
| 718 |
return l($text, BITCACHE_ALIAS . '/' . $id, $options);
|
| 719 |
}
|
| 720 |
|
| 721 |
function bitcache_resolve_id($id, array $options = array('absolute' => TRUE)) {
|
| 722 |
$options += array('prefix' => '', 'language' => array());
|
| 723 |
return url(BITCACHE_ALIAS . '/' . $id, $options);
|
| 724 |
}
|
| 725 |
|
| 726 |
function bitcache_resolve_uri($uri, array $options = array('absolute' => TRUE)) {
|
| 727 |
return ($id = bitcache_uri_to_id($uri)) ? bitcache_resolve_id($id, $options) : FALSE;
|
| 728 |
}
|
| 729 |
|
| 730 |
function bitcache_uri($id) {
|
| 731 |
return 'bitcache://' . $id;
|
| 732 |
}
|
| 733 |
|
| 734 |
function bitcache_uri_to_id($uri) {
|
| 735 |
return preg_match('!^bitcache://([0-9a-f]{40})$!', $uri, $matches) ? $matches[1] : NULL; // FIXME
|
| 736 |
}
|
| 737 |
|
| 738 |
function bitcache_id($data) {
|
| 739 |
return sha1($data); // FIXME
|
| 740 |
}
|
| 741 |
|
| 742 |
function bitcache_id_file($data) {
|
| 743 |
return sha1_file($data); // FIXME
|
| 744 |
}
|
| 745 |
|
| 746 |
function bitcache_exists($id) {
|
| 747 |
return bitcache_op('exists', $id);
|
| 748 |
}
|
| 749 |
|
| 750 |
function bitcache_get($id) {
|
| 751 |
return bitcache_op('get', $id);
|
| 752 |
}
|
| 753 |
|
| 754 |
function bitcache_get_stream($id) {
|
| 755 |
return ($stream = bitcache_get($id)) ? $stream->open('rb') : NULL;
|
| 756 |
}
|
| 757 |
|
| 758 |
function bitcache_get_contents($id) {
|
| 759 |
return ($stream = bitcache_get($id)) ? $stream->data() : NULL;
|
| 760 |
}
|
| 761 |
|
| 762 |
function bitcache_get_path($id, $file_only = FALSE) {
|
| 763 |
if (($stream = bitcache_get($id))) {
|
| 764 |
if (!($path = $stream->path()) && $file_only) {
|
| 765 |
$path = bitcache_tmpname();
|
| 766 |
|
| 767 |
if (($data = $stream->open('rb'))) {
|
| 768 |
stream_copy_to_stream($stream->open('rb'), $file = fopen($path, 'wb'));
|
| 769 |
$stream->close();
|
| 770 |
fclose($file);
|
| 771 |
}
|
| 772 |
else {
|
| 773 |
file_put_contents($path, $stream->data());
|
| 774 |
}
|
| 775 |
}
|
| 776 |
return $path;
|
| 777 |
}
|
| 778 |
return NULL;
|
| 779 |
}
|
| 780 |
|
| 781 |
function bitcache_get_size($id) {
|
| 782 |
return ($stream = bitcache_get($id)) ? $stream->size() : NULL;
|
| 783 |
}
|
| 784 |
|
| 785 |
function bitcache_get_type($id) {
|
| 786 |
if (module_exists('rdf')) {
|
| 787 |
$uri = bitcache_uri($id);
|
| 788 |
// TODO: query RDF if available.
|
| 789 |
}
|
| 790 |
return ($stream = bitcache_get($id)) ? $stream->type() : NULL;
|
| 791 |
}
|
| 792 |
|
| 793 |
function bitcache_put($id, $data) {
|
| 794 |
return bitcache_op('put', $id, $data);
|
| 795 |
}
|
| 796 |
|
| 797 |
function bitcache_put_file($id, $filepath, $move = FALSE) {
|
| 798 |
return bitcache_op('put_file', $id, $filepath, $move);
|
| 799 |
}
|
| 800 |
|
| 801 |
function bitcache_delete($id) {
|
| 802 |
return bitcache_op('delete', $id);
|
| 803 |
}
|
| 804 |
|
| 805 |
function bitcache_op($op) {
|
| 806 |
// TODO: static cache for repository objects.
|
| 807 |
$args = array_slice(func_get_args(), 1);
|
| 808 |
$repo = bitcache_get_repository(isset($GLOBALS['bitcache_repository']) ? $GLOBALS['bitcache_repository'] : NULL);
|
| 809 |
return call_user_func_array(array($repo, $op), $args);
|
| 810 |
}
|
| 811 |
|
| 812 |
//////////////////////////////////////////////////////////////////////////////
|
| 813 |
// Bitcache API helpers
|
| 814 |
|
| 815 |
/**
|
| 816 |
* Synchronizes repositories using the Bitcache command-line tools.
|
| 817 |
*/
|
| 818 |
function bitcache_sync(array $repos = array(), array $options = array()) {
|
| 819 |
return bitcache_exec(BITCACHE_EXEC . ' sync', NULL, $options, implode(' ', $repos));
|
| 820 |
}
|
| 821 |
|
| 822 |
/**
|
| 823 |
* Executes a 'bit' command using exec()/popen().
|
| 824 |
*/
|
| 825 |
function bitcache_exec($command, $mode = NULL, array $options = array()) {
|
| 826 |
$config = bitcache_get_repositories('config');
|
| 827 |
|
| 828 |
if (file_put_contents($config_file = bitcache_tmpname(), bitcache_yaml($config))) {
|
| 829 |
$options = array_merge(array('config' => $config_file), $options);
|
| 830 |
|
| 831 |
foreach ($options as $k => $v) {
|
| 832 |
$command .= ' --' . $k . ($v === TRUE ? '' : '=' . escapeshellarg((string)$v));
|
| 833 |
}
|
| 834 |
$arguments = array_slice(func_get_args(), 3);
|
| 835 |
$command = trim($command . ' ' . implode(' ', array_map('escapeshellarg', $arguments)));
|
| 836 |
|
| 837 |
if (!$mode) {
|
| 838 |
exec($command . ' 2>&1', $output, $result);
|
| 839 |
return $result === 0 ? $output : FALSE;
|
| 840 |
}
|
| 841 |
return popen($command, $mode);
|
| 842 |
}
|
| 843 |
}
|
| 844 |
|
| 845 |
/**
|
| 846 |
* Returns a string containing a Bitcache configuration file in YAML format.
|
| 847 |
*/
|
| 848 |
function bitcache_yaml($config) {
|
| 849 |
$output = array();
|
| 850 |
foreach ($config as $name => $cfg) {
|
| 851 |
$output[] = "$name:";
|
| 852 |
foreach ($cfg as $key => $value) {
|
| 853 |
$value = !is_bool($value) ? $value : ($value ? 'yes' : 'no');
|
| 854 |
$output[] = " $key: $value";
|
| 855 |
}
|
| 856 |
$output[] = '';
|
| 857 |
}
|
| 858 |
return implode("\n", $output);
|
| 859 |
}
|
| 860 |
|
| 861 |
/**
|
| 862 |
* Returns a path to a temporary file in Drupal's temporary directory.
|
| 863 |
*/
|
| 864 |
function bitcache_tmpname($register = TRUE) {
|
| 865 |
if (($path = tempnam(file_directory_temp(), 'drupal_bitcache_')) && $register) {
|
| 866 |
global $user;
|
| 867 |
db_query("INSERT INTO {files} (fid, uid, filename, filepath, filemime, filesize, status, timestamp) VALUES (NULL, %d, '%s', '%s', '%s', 0, %d, %d)", $user->uid, basename($path), $path, 'application/octet-stream', FILE_STATUS_TEMPORARY, time());
|
| 868 |
}
|
| 869 |
return $path;
|
| 870 |
}
|
| 871 |
|
| 872 |
function bitcache_token_replace($text) {
|
| 873 |
if (module_exists('token')) {
|
| 874 |
module_load_include('inc', 'bitcache', 'bitcache.token');
|
| 875 |
return token_replace($text);
|
| 876 |
}
|
| 877 |
else { // simple fallback token support
|
| 878 |
$tokens = array(
|
| 879 |
'[file-directory-path]' => file_directory_path(),
|
| 880 |
'[file-directory-temp]' => file_directory_temp(),
|
| 881 |
'[site-host]' => $_SERVER['HTTP_HOST'],
|
| 882 |
);
|
| 883 |
return str_replace(array_keys($tokens), array_values($tokens), $text);
|
| 884 |
}
|
| 885 |
}
|