uuid_features.module 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. <?php
  2. /**
  3. * Implements hook_menu().
  4. */
  5. function uuid_features_menu() {
  6. $items['admin/config/content/uuid_features'] = array(
  7. 'access arguments' => array('administer site configuration'),
  8. 'page callback' => 'drupal_get_form',
  9. 'page arguments' => array('uuid_features_settings'),
  10. 'title' => 'UUID Features Integration',
  11. 'description' => 'Configure the settings for UUID Features Integration.',
  12. );
  13. return $items;
  14. }
  15. /**
  16. * Implements hook_features_api().
  17. */
  18. function uuid_features_features_api() {
  19. $components = array();
  20. $components['uuid_node'] = array(
  21. 'name' => t('Content'),
  22. 'feature_source' => TRUE,
  23. 'default_hook' => 'uuid_features_default_content',
  24. 'default_file' => FEATURES_DEFAULTS_INCLUDED,
  25. 'file' => drupal_get_path('module', 'uuid_features') . '/includes/uuid_node.features.inc',
  26. );
  27. if (module_exists('taxonomy')) {
  28. $components['uuid_term'] = array(
  29. 'name' => t('Taxonomy Term'),
  30. 'feature_source' => TRUE,
  31. 'default_hook' => 'uuid_features_default_terms',
  32. 'default_file' => FEATURES_DEFAULTS_INCLUDED,
  33. 'file' => drupal_get_path('module', 'uuid_features') . '/includes/uuid_term.features.inc',
  34. );
  35. }
  36. // Depends on http://drupal.org/node/808690
  37. if (function_exists('uuid_file_insert')) {
  38. $components['uuid_file'] = array(
  39. 'name' => t('File'),
  40. 'default_hook' => 'uuid_features_default_files',
  41. 'default_file' => FEATURES_DEFAULTS_INCLUDED,
  42. 'file' => drupal_get_path('module', 'uuid_features') . '/includes/uuid_file.features.inc',
  43. );
  44. }
  45. return $components;
  46. }
  47. /**
  48. * Load all include files for enabled modules that this module provides
  49. * on-behalf-of functionality for.
  50. */
  51. function uuid_features_load_module_includes() {
  52. static $loaded = FALSE;
  53. if (!$loaded) {
  54. $inc_path = drupal_get_path('module', 'uuid_features') . '/includes/modules';
  55. foreach (module_list() as $module) {
  56. $file = "$inc_path/$module.inc";
  57. if (file_exists($file)) {
  58. include_once DRUPAL_ROOT . '/' . $file;
  59. }
  60. }
  61. $loaded = TRUE;
  62. }
  63. }
  64. /**
  65. * Implements hook_features_pipe_COMPONENT_alter().
  66. *
  67. * When exporting a vocabulary, include its terms.
  68. */
  69. function uuid_features_features_pipe_taxonomy_alter($pipe, $data, $export) {
  70. if ($vocab = taxonomy_vocabulary_machine_name_load($data)) {
  71. foreach (taxonomy_get_tree($vocab->vid) as $term) {
  72. uuid_term_features_get_dependencies($export, $term->uuid);
  73. }
  74. $pipe['uuid_term'] = $export['features']['uuid_term'];
  75. }
  76. }
  77. /**
  78. * Menu callback to configure module settings.
  79. */
  80. function uuid_features_settings($form, &$form_state) {
  81. $vocabularies = array();
  82. foreach (taxonomy_vocabulary_get_names() as $machine_name => $properties) {
  83. $vocabularies[$machine_name] = $properties->name;
  84. }
  85. $form['file']['uuid_features_file_types'] = array(
  86. '#type' => 'checkboxes',
  87. '#title' => t('Files exported for vocabularies'),
  88. '#default_value' => variable_get('uuid_features_file_types', array()),
  89. '#options' => $vocabularies,
  90. '#description' => t('Which vocabularies should export file fields?'),
  91. );
  92. $form['file']['uuid_features_file_mode'] = array(
  93. '#type' => 'radios',
  94. '#title' => t('File export mode'),
  95. '#default_value' => variable_get('uuid_features_file_mode', 'inline'),
  96. '#options' => array(
  97. 'inline' => t('Inline Base64'),
  98. 'local' => t('Local file export'),
  99. 'remote' => t('Remote file export, URL')
  100. ),
  101. '#description' => t('Should file exports be inline inside the export code, a local path to the file, or a URL? Inline Base64 is the easiest option to use but can sometimes exceed PHP post limits, local and remote modes are more useful for power users. <em>NOTE: Remote mode only works with a public files directory.</em>'),
  102. );
  103. $form['file']['uuid_features_file_assets_path'] = array(
  104. '#type' => 'textfield',
  105. '#title' => t('Local file field assets path'),
  106. '#size' => 60,
  107. '#maxlength' => 255,
  108. '#default_value' => variable_get('uuid_features_file_assets_path', ''),
  109. '#description' => t(
  110. 'Optionally, copy files to this path when the node is exported.
  111. The primary advantage of this is to divert exported files into a
  112. safe location so they can be committed to source control (eg: SVN,
  113. CVS, Git). <em>Tip: For install profile developers, setting this
  114. path to <code>profiles/my_profile/uuid_features_assets</code> may be
  115. useful.</em>'
  116. ),
  117. '#required' => FALSE,
  118. '#states' => array(
  119. 'visible' => array(
  120. ':input[name=uuid_features_file_mode]' => array('value' => 'local'),
  121. ),
  122. ),
  123. );
  124. $form['file']['uuid_features_file_supported_fields'] = array(
  125. '#type' => 'textfield',
  126. '#title' => t('Supported file field types'),
  127. '#default_value' => variable_get('uuid_features_file_supported_fields', 'file, image'),
  128. '#maxlength' => 512,
  129. '#description' => t('Comma seperated list of file field types to detect for export/import.'),
  130. );
  131. return system_settings_form($form);
  132. }
  133. /**
  134. * Detects remote and local file exports and imports accordingly.
  135. *
  136. * @param &$file
  137. * The file, passed by reference.
  138. * @return TRUE or FALSE
  139. * Depending on success or failure. On success the $file object will
  140. * have a valid $file->fid attribute.
  141. */
  142. function _uuid_features_file_field_import_file(&$file) {
  143. // This is here for historical reasons to support older exports. It can be
  144. // removed in the next major version.
  145. $file->uri = strtr($file->uri, array('#FILES_DIRECTORY_PATH#' => 'public:/'));
  146. // The file is already in the right location AND either the
  147. // uuid_features_file_path is not set or the uuid_features_file_path and filepath
  148. // contain the same file
  149. if (is_file($file->uri) &&
  150. (
  151. (!isset($file->uuid_features_file_path) || !is_file($file->uuid_features_file_path)) ||
  152. (
  153. is_file($file->uuid_features_file_path) &&
  154. filesize($file->uri) == filesize($file->uuid_features_file_path) &&
  155. strtoupper(dechex(crc32(file_get_contents($file->uri)))) ==
  156. strtoupper(dechex(crc32(file_get_contents($file->uuid_features_file_path))))
  157. )
  158. )
  159. ) {
  160. // Keep existing file if it exists already at this uri (see also #1023254)
  161. // Issue #1058750.
  162. $query = db_select('file_managed', 'f')
  163. ->fields('f', array('fid'))
  164. ->condition('uri', $file->uri)
  165. ->execute()
  166. ->fetchCol();
  167. if (!empty($query)) {
  168. watchdog('uuid_features', 'kept existing managed file at uri "%uri"', array('%uri' => $file->uri), WATCHDOG_NOTICE);
  169. $file = file_load(array_shift($query));
  170. }
  171. $file = file_save($file);
  172. }
  173. elseif (isset($file->uuid_features_file_data)) {
  174. $directory = drupal_dirname($file->uri);
  175. if (file_prepare_directory($directory, FILE_CREATE_DIRECTORY)) {
  176. if (file_put_contents($file->uri, base64_decode($file->uuid_features_file_data))) {
  177. $file = file_save($file);
  178. }
  179. }
  180. }
  181. // The file is in a local location, move it to the
  182. // destination then finish the save
  183. elseif (isset($file->uuid_features_file_path) && is_file($file->uuid_features_file_path)) {
  184. $directory = drupal_dirname($file->uri);
  185. if (file_prepare_directory($directory, FILE_CREATE_DIRECTORY)) {
  186. // The $file->uuid_features_file_path is passed to reference, and modified
  187. // by file_unmanaged_copy(). Making a copy to avoid tainting the original.
  188. $uuid_features_file_path = $file->uuid_features_file_path;
  189. file_unmanaged_copy($uuid_features_file_path, $directory, FILE_EXISTS_REPLACE);
  190. // At this point the $file->uuid_features_file_path will contain the
  191. // destination of the copied file
  192. //$file->uri = $uuid_features_file_path;
  193. $file = file_save($file);
  194. }
  195. }
  196. // The file is in a remote location, attempt to download it
  197. elseif (isset($file->uuid_features_file_url)) {
  198. // Need time to do the download
  199. ini_set('max_execution_time', 900);
  200. $temp_path = file_directory_temp() . '/' . md5(mt_rand()) . '.txt';
  201. if (($source = fopen($file->uuid_features_file_url, 'r')) == FALSE) {
  202. drupal_set_message(t("Could not open '@file' for reading.", array('@file' => $file->uuid_features_file_url)));
  203. return FALSE;
  204. }
  205. elseif (($dest = fopen($temp_path, 'w')) == FALSE) {
  206. drupal_set_message(t("Could not open '@file' for writing.", array('@file' => $file->uri)));
  207. return FALSE;
  208. }
  209. else {
  210. // PHP5 specific, downloads the file and does buffering
  211. // automatically.
  212. $bytes_read = @stream_copy_to_stream($source, $dest);
  213. // Flush all buffers and wipe the file statistics cache
  214. @fflush($source);
  215. @fflush($dest);
  216. clearstatcache();
  217. if ($bytes_read != filesize($temp_path)) {
  218. drupal_set_message(t("Remote export '!url' could not be fully downloaded, '@file' to temporary location '!temp'.", array('!url' => $file->uuid_features_file_url, '@file' => $file->uri, '!temp' => $temp_path)));
  219. return FALSE;
  220. }
  221. // File was downloaded successfully!
  222. else {
  223. if (!@copy($temp_path, $file->uri)) {
  224. unlink($temp_path);
  225. drupal_set_message(t("Could not move temporary file '@temp' to '@file'.", array('@temp' => $temp_path, '@file' => $file->uri)));
  226. return FALSE;
  227. }
  228. unlink($temp_path);
  229. $file->filesize = filesize($file->uri);
  230. $file->filemime = file_get_mimetype($file->uri);
  231. }
  232. }
  233. fclose($source);
  234. fclose($dest);
  235. $file = file_save($file);
  236. }
  237. // Unknown error
  238. else {
  239. drupal_set_message(t("Unknown error occurred attempting to import file: @filepath", array('@filepath' => $file->uri)), 'error');
  240. return FALSE;
  241. }
  242. return TRUE;
  243. }