/[drupal]/contributions/modules/dbfm/dbfm.module
ViewVC logotype

Contents of /contributions/modules/dbfm/dbfm.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.3 - (show annotations) (download) (as text)
Sat Oct 20 22:33:01 2007 UTC (2 years, 1 month ago) by rooey
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-5
Changes since 1.2: +9 -6 lines
File MIME type: text/x-php
by Rooey. Fixed an issue with popups & TinyMCE. More CSS styling touches. Pop-ups working now.
Properties now display correctly.
1 <?php
2 /* $Id: dbfm.module, Exp $ */
3
4 // why on earth does this file always come up aas a particular font?
5
6
7 //IMPORTANTS NOTES: None of this has been tested for databases other than mysql
8 // an out of the box LAMP installation will NOT work with large file sizes
9 // PHP.ini needs the post size, the memory and the upload size increased
10 // the mysql my.cnf file needs to be modified to increase just about all of the settings (but especially those for packet size)
11
12 // note that if another module adds an icon underneath text areas you may have to alter their code to ensure they use a span
13 // rather than a div (to get the icons in line)
14 // still to do - a switch MUST be added to prevent compressed files being further compressed and to avoid uncomressing them on
15 // the way out. I've provided a list of files not to be compressed but I'm not sure about things like MP3 etc which are already
16 // sorta compressed?
17
18 // ** we'll need to include the license for the greybox (or whatever) in our documentation
19
20 require_once 'dbfm_file.inc';
21
22 define('FLUSH', -1);
23
24 define('REPLACE_RENAME', 0);
25 define('REPLACE_DELETE', 1);
26 define('RENAME_NEW', 2);
27 define('CANCEL', 3);
28
29 /*
30 a few quick notes on the filter that allows dbfm to attach and embed code.
31 You need to go to the Input Format section of admin in order to setup the dbfm filter
32 just go to settings filters and switch on (check) the dbFM filter
33
34 */
35
36 /**
37 * Implementation of hook_help().
38 */
39 function dbfm_help($section) {
40 switch ($section) {
41 case 'admin/help#dbfm':
42 $output = '<p>'.t('dbFM is a hierarchical file manager.
43 dbFM actually stores your files in the database as compressed blobs -
44 Files are compressed as they are imported and uncompressed when you
45 need to access them. The files are presented to the user as though stored
46 in a hierachical file system (in the same way as they would appear on
47 your local storage drives). This ability to hierarchically arrange files
48 greatly enhances the manageability of large collections of data.').'</p>'.
49 '<p>'.t('dbFM is based on webFM (written by Rob Milne) and not all of the
50 legacy filesystem code has been stripped out yet - dbfm still uses
51 <b>includes/file.inc</b> which manages the file system path. The <b>Root
52 Directory</b> path is relative to the file system path set at %file-sys
53 and must be prefaced with a "/".', array('%file-sys' => url('admin/settings/file-system')))
54 .'</p>'.'<p>'.t('dbFM uses ajax and javascript extensively to provide
55 application intensive functionality such as file/dir move via drag and drop.
56 The right mouse button click provides context sensitive menus for user
57 selection. Javascript MUST be enabled for dbfm to function.').'</p>'.
58 '<p>'.t('dbFM presents a left hand block to represent the directory
59 tree and a right hand block to list the contents of the current
60 directory.').'</p>'.'<p>'.t('dbFM allows content stored in its filesystem
61 to be linked to nodes or, in the case of images, embedded into nodes.
62 dbFM has also been written to interface with the tinyMCE editor for
63 rich text editing of nodes. Linking an embedding are both acheived using
64 filters - see installation instructions for more details').'</p>';
65 return $output;
66
67 case 'admin/modules#description':
68 return t('Enable the Web File Manager.');
69 }
70 }
71
72 /**
73 * used to generate random numbers (with srand) to make temporary filenames while 'blobbing'
74 */
75 function make_seed()
76 {
77 list($usec, $sec) = explode(' ', microtime());
78 return (float) $sec + ((float) $usec * 100000);
79 }
80
81
82 /**
83 * Implementation of hook_settings().
84 */
85 function dbfm_admin_settings() {
86
87 $form['dbfm_root_dir'] =
88 array('#type' => 'textfield',
89 '#title' => t('Root directory'),
90 '#default_value' => variable_get('dbfm_root_dir', '/dbfm'),
91 '#maxlength' => '100',
92 '#size' => '70',
93 '#description' => t('Root directory used to present the filebrowser interface. Users will not be able
94 <br />to go up from this folder.
95 <br /><br />This path is relative to "File system path" set in admin/settings/file-system and
96 <br />must be preceeded with a slash.')
97 );
98
99 $modulepath = drupal_get_path('module', 'dbfm');
100 $form['dbfm_icon_dir'] =
101 array('#type' => 'textfield',
102 '#title' => t('Icon directory'),
103 '#default_value' => variable_get('dbfm_icon_dir', $modulepath. '/image/icon'),
104 '#maxlength' => '100',
105 '#size' => '70',
106 '#description' => t('Name of directory where file type icons are stored (relative to base url).')
107 );
108
109 $form['attach']['dbfm_attach_desc'] =
110 array('#type' => 'checkbox',
111 '#title' => t('Add description metadata'),
112 '#default_value' => variable_get('dbfm_attach_desc', ''),
113 '#description' => t('Check this box to interleave file description metadata rows to file rows.')
114 );
115
116
117 $form['dbfm_debug'] =
118 array('#type' => 'checkbox',
119 '#title' => t('dbFM javascript debug'),
120 '#default_value' => variable_get('dbfm_debug', ''),
121 '#description' => t('Check this box for javascript debug messaging.')
122 );
123
124 /* $form['dbfm_cron'] =
125 array('#type' => 'checkbox',
126 '#title' => t('dbFM cron'),
127 '#default_value' => variable_get('dbfm_cron', ''),
128 '#description' => t('Check this box to enable cleanup of orphaned file records in the database.
129 <br />NOTE: Use with caution - behaviour is to delete all file records without a
130 <br />valid file path. Manually renaming a dbFM directory (ie: via OS shell)
131 <br />and then running cron will delete all dbfm_file table entries for that
132 <br />directory and it\'s sub-directories.')
133 );
134 */
135 $form['dbfm_nozip'] =
136 array('#type' => 'textarea',
137 '#title' => t('Don\'t compress'),
138 '#default_value' => variable_get('dbfm_nozip', 'arc arj as b64 bin btoa bz cab cpt gz hqx iso lha lzh mim mme pak pf rar sea sit sitx tar tbz tbz2 tgz uu uue z zip zoo'),
139 '#description' => t('Files that are already compressed and should be stored as-is in the database (use space delimited with no leading dot)') );
140
141 //fill in which pages need to use dbfm
142 $form['dbfm_pages'] =
143 array('#type' => 'textarea',
144 '#title' => t('Activate dbfm on specific page types'),
145 '#default_value' => variable_get('dbfm_pages', "node edit,\nnode add"),
146 '#description' => t('Enter one page type per line with a comma at the end of the line (for neatness). Example types might be "node" for all node pages or "node add" which limits the user to having greybox only when adding nodes. You shouldn\'t include the slashes. The reason you would want to disallow dbfm is because it saves loading the java code into the page header - pages should load faster! and it reduces possible interactions with other javascript'));
147
148 //add settings for attaching (linking to nodes), keep them in their own fieldset
149 $form['dbfm_attach'] =
150 array('#type' => 'fieldset',
151 '#title' => t('Link / Embed Settings'),
152 '#collapsible' => TRUE,
153 '#collapsed' => TRUE);
154
155 //set whether to allow attach / embed on different node types, build a load of check boxes
156 $types = node_get_types();
157 foreach ($types as $type) {
158 if ($type->type) {
159 $form['dbfm_attach']['dbfm_attach_'.$type->type] =
160 array('#type' => 'checkbox',
161 '#title' => t('Link / Embed to - ' . $type->type),
162 '#default_value' => variable_get('dbfm_attach_'.$type->type, 1),
163 '#description' => t('Should node type ' . $type->type . ' allow users to link and embed files via dbFM?'),
164 );
165 }
166 }
167
168
169 // this is new to me, returns an array of valid roles (avoids anonymous users)
170 $roles = user_roles(1,0);
171
172 // Flush extensions regex cache for upload and db enum
173 // ZZZZZZZZZZ dunno what this is about??
174 dbfm_get_extensions_regex(FLUSH);
175
176 foreach ($roles as $rid => $role) {
177 $form["settings_role_".$rid] =
178 array('#type' => 'fieldset',
179 '#title' => t('Settings for @role', array('@role' => $role)),
180 '#collapsible' => TRUE,
181 '#collapsed' => TRUE
182 );
183
184 $form["settings_role_".$rid]["dbfm_extensions_".$rid] =
185 array('#type' => 'textfield',
186 '#title' => t('Permitted file extensions'),
187 '#default_value' => variable_get("dbfm_extensions_".$rid, "ai doc dot eps exe gif gxd gz html htm ind jpg jpeg pdf png ppt pps psd qxd swf tif tiff txt xls zip"),
188 '#maxlength' => 255,
189 '#description' => t('Extensions that users in this role can upload. (use space delimited with no leading dot).')
190 );
191
192 $form["settings_role_".$rid]["dbfm_uploadsize_".$rid] =
193 array('#type' => 'textfield',
194 '#title' => t('Maximum file size per upload'),
195 '#default_value' => variable_get("dbfm_uploadsize_".$rid, 1),
196 '#size' => 5,
197 '#maxlength' => 5,
198 '#description' => t('The maximum size of a file a user can upload (in megabytes).')
199 );
200
201 $form["settings_role_".$rid]["dbfm_usersize_".$rid] =
202 array('#type' => 'textfield',
203 '#title' => t('Total file size per user'),
204 '#default_value' => variable_get("dbfm_usersize_".$rid, 10),
205 '#size' => 5,
206 '#maxlength' => 5,
207 '#description' => t('The maximum size of all files a user can have on the site (in megabytes).')
208 );
209 }
210 return system_settings_form($form);
211 }
212
213 /**
214 * Implementation of hook_perm().
215 */
216 function dbfm_perm() {
217 return array('access dbfm', 'attach dbFM files', 'see dbfm_attachments');
218 }
219
220 /**
221 * Implementation of hook_menu(). ZZZZ I need to change this to say "Document Tool"
222 */
223 function dbfm_menu($maycache) {
224 $items = array();
225 if ($maycache) {
226 $items[] = array(
227 'title' => t('Database File Manager'),
228 'path' => 'dbfm',
229 'access' => user_access('access dbfm'),
230 'callback' => 'dbfm_main');
231
232 //build the attachment browser
233 $items[] = array(
234 'title' => t('Attach popup launcher'),
235 'path' => 'dbfm_attachit',
236 'access' => user_access('access dbfm'),
237 'callback' => 'dbfm_attachit',
238 'type' => MENU_CALLBACK);
239
240 //build the search screen
241 $items[] = array(
242 'title' => t('Search screen'),
243 'path' => 'dbfm_searchit',
244 'access' => user_access('access dbfm'),
245 'callback' => 'dbfm_searchit',
246 'type' => MENU_CALLBACK);
247
248 //build the properties screen
249 $items[] = array(
250 'title' => t('Properties screen'),
251 'path' => 'dbfm_propertit',
252 'access' => user_access('access dbfm'),
253 'callback' => 'dbfm_propertit',
254 'type' => MENU_CALLBACK);
255
256 //build the upload screen
257 $items[] = array(
258 'title' => t('Upload screen'),
259 'path' => 'dbfm_uploadit',
260 'access' => user_access('access dbfm'),
261 'callback' => 'dbfm_uploadit',
262 'type' => MENU_CALLBACK);
263
264 //build the help screen
265 $items[] = array(
266 'title' => t('Help screen'),
267 'path' => 'dbfm_helpit',
268 'access' => user_access('access dbfm'),
269 'callback' => 'dbfm_helpit',
270 'type' => MENU_CALLBACK);
271
272 $items[] = array(
273 'title' => t('DB File Manager'),
274 'path' => 'dbfm_js',
275 'access' => user_access('access dbfm'),
276 'callback' => 'dbfm_ajax',
277 'type' => MENU_CALLBACK);
278
279 //call the submit for the upload
280 $items[] = array(
281 'title' => t('DB File Manager'),
282 'path' => 'dbfm/upload',
283 'access' => user_access('access dbfm'),
284 'callback' => 'dbfm_upload',
285 'type' => MENU_CALLBACK);
286
287 $items[] = array(
288 'title' => t('File Not Found'),
289 'path' => 'dbfm_send',
290 'access' => user_access('see dbfm_attachments'),
291 'callback' => 'dbfm_send_file',
292 'type' => MENU_CALLBACK);
293
294 $items[] = array('path' => 'admin/settings/dbfm',
295 'title' => t('DBFM Settings'),
296 'description' => t('Configure DBFM.'),
297 'callback' => 'drupal_get_form',
298 'callback arguments' => array('dbfm_admin_settings'),
299 'access' => user_access('administer site configuration'),
300 'type' => MENU_NORMAL_ITEM);
301 }
302 else {
303 //used to add information to the header of all other modules that need dbfm
304
305 //rather than adding dbfm to every header we just add it to those pages that need it
306 //that saves the huge overhead of adding it eveywhere.
307 $path = drupal_get_path_alias($_GET['q']);
308 $page_list = variable_get('dbfm_pages', '');
309
310 //split the page list into an array of strings
311 $page_array = explode(',', $page_list);
312
313 foreach ($page_array as $pagetest) {
314
315 //now, wherever there's a space, split the page line into an array
316 //there might be no spaces but we just don't care
317 $page_elements = explode(' ',$pagetest);
318 //now we have to check that each element can be matched to the path
319 //and occurs in order
320 foreach ($page_elements as $matchthis) {
321 $mypos = stripos($path,trim($matchthis));
322 if ($mypos === FALSE) {
323 //nope it's not a match (bombs out on 1st fail)
324 $i = -1;
325 break;
326 }
327 $i = $mypos;
328 }
329 if ($i > 0) {
330 $path = drupal_get_path('module', 'dbfm');
331 drupal_add_css($path .'/css/dbfm.css');
332 drupal_add_js($path .'/js/dbfm.js');
333 }
334 }
335 }
336 return $items;
337 }
338
339
340 /**
341 * Implementation of hook_form_alter().
342 * I wasn't happy with Rob's form - I've moved some bits into the admin screen
343 */
344
345 function dbfm_form_alter($form_id, &$form) {
346
347 //test here to see that we are allowed to link and embed on this type of form
348 check_node($form_id);
349
350 }
351
352
353
354 /**
355 * add all the necessary dbfm CSS/JS to the header. Make sure we only do it once
356 */
357 function dbfm_include() {
358 // static $include;
359
360 //by declaring $include static it remembers its last setting every time this is called
361 // if (!$include) {
362 $modulepath = drupal_get_path('module', 'dbfm');
363 drupal_add_js($modulepath .'/js/dbfm.js');
364 drupal_add_css($modulepath .'/css/dbfm.css');
365 drupal_add_js('misc/collapse.js'); //why do we need this? isn't it there by default??
366 // $include = true;
367 // }
368 }
369
370 // this checks whether we're on a node form and whether it's the correct type of node form
371 // it's initially called by the form alter (which passes the form_id) subsiquent calls
372 // when testing the form element just call this with a null parameter - the result of the previous test
373 // having been stored in the static variable
374 function check_node($form_id) {
375
376 static $retval = FALSE;
377
378 if ($form_id == NULL) {
379 return $retval;
380 }
381
382 //see whether it's a node form of some sort
383 $posn = strpos($form_id,"_node");
384 if ($posn == FALSE) {
385 // not a node form
386 $retval = FALSE;
387 return FALSE;
388 }
389
390 $nodetype = substr($form_id,0,$posn);
391
392 //if we're allowed to attach to this type of node
393 if (variable_get('dbfm_attach_' . $nodetype, 1) && user_access('attach dbFM files')) {
394 $retval = TRUE;
395 return TRUE;
396 }
397 $retval = FALSE;
398 return FALSE;
399 }
400
401
402 //ZZZZZZZZZZis this still needed??
403 /**
404 * Theme the attachment form.
405 * Note: required to output prefix/suffix.
406 */
407 function theme_dbfm_attach_attached_form($form) {
408 $output = drupal_render($form);
409 return $output;
410 }
411
412
413 /**
414 * Helper function to return the defined sizes (or proper defaults).
415 */
416 function _dbfm_get_sizes() {
417 // the entry in the variables table is an array of all the possible sizes with a 100x100 thumbnail as default
418 // ZZZZ this will have to be stripped out to use the static data table - the only other option would be
419 $sizes = variable_get('dbfm_sizes', array(array('width' => 100, 'height' => 100, 'label' => 'thumbnail'),
420 ));
421 // use an anonymous function to filter the $sizes array
422 return array_filter($sizes, create_function('$size', 'return !empty($size["label"]);'));
423 }
424
425
426 // awkward one here, the module won't let you resize larger than the original - but since we don't know how bg the original is
427 // we can't vet for this
428 function dbfm_settings_sizes_form() {
429
430 $sizes = _dbfm_get_sizes();
431
432 $form['#type'] = 'item';
433 $form['#description'] = t('Select various pixel dimensions, "thumbnail" is required.
434 For each Label and dimension you enter a new "right-click" menu option will become available in dbFM for image files.
435 Clicking the menu item with resize the image based on these settings.');
436 $form['#tree'] = TRUE;
437 $form['#theme'] = 'dbfm_settings_sizes_form';
438 for ($i = 0; $i < 5; $i++) {
439 $form[$i]['label'] = array('#type' => 'textfield', '#default_value' => $sizes[$i]['label'], '#size' => 25);
440 if (in_array($sizes[$i]['label'], array('thumbnail'))) {
441 $form[$i]['label']['#attributes'] = array('disabled' => 'disabled');
442 $form[$i]['label']['#value'] = $sizes[$i]['label'];
443 }
444 $form[$i]['width'] = array('#type' => 'textfield', '#default_value' => $sizes[$i]['width'], '#size' => 5, '#maxlength' => 5);
445 $form[$i]['height'] = array('#type' => 'textfield', '#default_value' => $sizes[$i]['height'], '#size' => 5, '#maxlength' => 5);
446 }
447
448 return $form;
449 }
450
451 function theme_dbfm_settings_sizes_form(&$form) {
452 $header = array(t('Label'), t('Width'), t('Height'));
453 foreach (element_children($form) as $key) {
454 $row = array();
455 $row[] = drupal_render($form[$key]['label']);
456 $row[] = drupal_render($form[$key]['width']);
457 $row[] = drupal_render($form[$key]['height']);
458 $rows[] = $row;
459
460 }
461 $output = theme('table', $header, $rows);
462 $output .= drupal_render($form);
463
464 return $output;
465 }
466
467
468 /**
469 * Helper func to associate the listing icon with the mime type
470 */
471 function _dbfm_get_icon($ext) {
472 // Try and find appropriate type
473 switch(strtolower($ext)) {
474 case 'image/gif':
475 case 'image/png':
476 case 'image/jpg':
477 case 'image/jpeg':
478 case 'image/bmp':
479 case 'image/tiff':
480 case 'jpg':
481 $icon = 'i.gif';
482 break;
483 case 'video/mpeg':
484 case 'video/quicktime':
485 case 'video/x-msvideo':
486 $icon = 'avi.gif';
487 break;
488 case 'audio/mpeg':
489 $icon = 'mp3.gif';
490 break;
491 case 'application/pdf':
492 $icon = 'pdf.gif';
493 break;
494 case 'application/zip':
495 case 'application/x-zip':
496 case 'application/x-gzip':
497 $icon = 'zip.gif';
498 break;
499 case 'application/msword':
500 $icon = 'doc.gif';
501 break;
502 case 'application/vnd.ms-excel':
503 $icon = 'xls.gif';
504 break;
505 default:
506 $icon = 'f.gif';
507 break;
508 }
509 return $icon;
510 }
511
512 /**
513 * Called by the upload form on submit
514 */
515 //UGHHH! I hate this bit of code. There are better ways of handling errors than all these nested if's
516 //for now I've just put a loop around the lot with a break for errors (a GOTO in disguise!)
517
518 function dbfm_upload () {
519 global $active_db;
520
521 drupal_set_message("Does it ever get back here?");
522
523 // files which are too large arrive with no path set - WHAT??
524
525 // a while loop was bunged in to make it easy to exit to the bottom
526 while (TRUE) {
527 $root_path = file_directory_path().variable_get('dbfm_root_dir', '');
528
529 $json_data = array();
530
531 //should be passed back the directory in the browser we want to put it in - surely we have a fid for that in the javascript?
532 //if not that would simplify matters ZZZZZZZZZZZZZZZZZZZ
533 if($_SESSION['upload_dir']) {
534 $dest = $_SESSION['upload_dir'];
535
536 if($dest) {
537 // Save new file uploads to tmp dir.
538 if(($file = file_check_upload('dbfm_upload')) != FALSE) {
539 if(dbfm_upload_validate($file, $err) === TRUE) {
540 // file has been put in temp and we have a valid file object
541
542 //need an extra check here to see whether the file already exists
543 //just do a simple search in the database
544 $qexist = db_query("SELECT * FROM {dbfm_file} WHERE fpath = '%s'",$dest . "/" . $file->filename);
545 $numret = db_num_rows($qexist);
546 if ($numret) {
547 drupal_set_message("File already exists in the database");
548 break;
549 }
550
551 //now if it's going to saved as a blob we need to do some work
552 $metadata = array();
553 $currentdate = date("Y-m-d H:i:s");
554 $metadata['fpath'] = $dest; //we're being sneaky here - we don't actually send the full path, we leave off the filename
555 $metadata['fname'] = $file->filename;
556 $metadata['flastmod'] = $currentdate;
557 $metadata['ftitle'] = $file->filename;
558 $metadata['fcreatedate'] = $currentdate;
559 $metadata['fdown'] = 0;
560
561 //before we compress the file lets fill in imagesize details into the database
562 // getimagesize returns an array of data about an image file
563 // the array has 5 elements, width, height, image type, a text string with width and height, and the mime type
564 // the @ symbol before the function call suppresses error messages (you need this because the file's not an
565 // image in most cases
566 if ($i = @getimagesize($file->filepath)) {
567 $metadata['fimagesize'] = $i[0] . 'x' . $i[1]; // the text string (couldn't use i[3], it was too verbose
568 $metadata['fimagew'] = (int) $i[0];
569 $metadata['fimageh'] = (int) $i[1];
570 }
571
572 $ext = explode('.', $file->filename);
573 $extension = $ext[count($ext)-1];
574
575 $frp = fopen($file->filepath, 'r');
576 $filecontent = fread($frp, $file->filesize);
577
578 //mysql doesn't need to encode and decode blobs - only dbs like postgress do that
579 if ($GLOBALS['db_type'] == 'mysql') {
580 //we'll escape nasty characters here and decide whether or not we need to compress the file
581 if (dbfm_compress($extension)) {
582 $metadata['fblob'] = mysql_real_escape_string(gzcompress($filecontent),$active_db);
583 }
584 else {
585 $metadata['fblob'] = mysql_real_escape_string($filecontent,$active_db);
586 }
587 }
588 else {
589 // non-mysql database
590 if (dbfm_compress($extension)) {
591 $metadata['fblob'] = gzcompress(db_encode_blob($filecontent));
592 }
593 else {
594 $metadata['fblob'] = db_encode_blob($filecontent);
595 }
596 }
597 fclose($frp);
598
599 //Insert file into database
600 if ($file_in_db = dbfm_dbinsert_file($file, $err, $metadata)) {
601 // file was inserted into the database
602
603 //we need to clear all the fields on the file upload form - HOW??
604 //do we re-draw the form?
605 //surely the reload upload function (below) should do this??
606
607 // we have to get rid of the temporary file
608 file_delete($file->filepath);
609 drupal_set_message(t('Upload success'));
610 }
611 else {
612 file_delete($file->filepath);
613 }
614 }
615 else {
616 drupal_set_message(t('file %s is not valid for upload', array('%s' => $file->filename)), error);
617 }
618 } else {
619 drupal_set_message(t('file_check_upload() failed: Check your php configuration to ensure that "max_file_upload" is greater than the file size you are attempting to upload.'), error);
620 }
621 }
622 else{
623 drupal_set_message(t('Invalid destination path: %dest', array('%dest' => $dest)), error);
624 }
625 } else {
626 // not a helpful message - I've added the path ... though it's unlikely to be filled if we've errored
627 drupal_set_message(t('Invalid upload path: %upload', array('%upload' => $_SESSION['upload_dir'])), error);
628 }
629 break;
630 } //end of big while-true loop
631
632 //we need to get rid of the greybox here - I think the problem is that there's no submit with our code
633
634 //aha reload only clears the upload box itself ZZZZZZZZZZZ
635 if(!isset($json_data['html'])) {
636 $json_data['html'] = dbfm_reload_upload('dbfm/upload');
637 }
638 print drupal_to_js(array('status' => TRUE, 'data' => $json_data));
639 exit();
640 }
641
642 /**
643 * Actually shows the upload form
644 */
645 function dbfm_reload_upload ($url, $confirm_form = '') {
646
647 $form = array();
648 if ($confirm_form) {
649 array_push($form, $confirm_form);
650 }
651 array_push($form, dbfm_upload_form($url));
652 //pass the name of the form and the form array
653 $form = form_builder('upload_js', $form);
654 $output = theme('status_messages') . drupal_render($form);
655 return $output;
656 }
657
658 /**
659 * Called by all ajax post requests
660 */
661 function dbfm_ajax () {
662
663 // declare the error array - may as well just do it once here
664 $err_arr[] = array();
665
666 if(isset($_POST["action"])) {
667 $root_path = file_directory_path().variable_get('dbfm_root_dir', '');
668 switch(trim(strtolower($_POST["action"]))) {
669 case "delete":
670 if(isset($_POST["param0"])) {
671
672 $source = trim(rawurldecode($_POST["param0"]));
673 $root = $root_path;
674
675 // prevent any ../ shenanigans
676 if($source && !ereg('\.\.', $source)) {
677 $ret = dbfm_delete($source, $err_arr);
678 dbfm_json(array('status' => $ret, 'data' => $err_arr));
679 $dir = is_dir($source) ? TRUE : FALSE;
680 //redraw the tree if we've deleted directories
681 if($ret && $dir)
682 unset($_SESSION['tree_'.$root]);
683 }
684 else {
685 dbfm_json(array('status' => FALSE, 'data' => 'illegal dir - ' . $source));
686 }
687 }
688 else
689 dbfm_json(array('status' => FALSE, 'data' => 'insufficient params'));
690 exit();
691 break;
692
693 //Create new directory
694 case "mkdir":
695 if(isset($_POST["param0"])) {
696 if(isset($_POST["param1"]))
697 $dest = $_POST["param1"];
698 else {
699 $dest = t("New_Folder");
700 }
701
702 $source = trim(rawurldecode($_POST["param0"]));
703
704 // second param is the right to rename if a dir of same name already
705 // exists in current folder
706 $ret = dbfm_mkdir($source, $dest, TRUE, $err_arr);
707 dbfm_json(array('status' => $ret, 'data' => $err_arr));
708 if($ret) {
709 unset($_SESSION['tree_'.$root]);
710 }
711 }
712 else {
713 dbfm_json(array('status' => FALSE, 'data' => 'insufficient params'));
714 }
715 exit();
716 break;
717
718 //Move a file or directory (drag and drop)
719 case "move":
720 if(isset($_POST["param0"]) && isset($_POST["param1"])) {
721 $source = trim(rawurldecode($_POST["param0"]));
722 $dest = trim(rawurldecode($_POST["param1"]));
723
724 // Destination path must different
725 if ($source != $dest) {
726 $ret = dbfm_move($source, $dest, $err_arr);
727 dbfm_json(array('status' => $ret, 'data' => $err_arr));
728 if($ret && $dir) {
729 unset($_SESSION['tree_'.$root]);
730 }
731 }
732 else {
733 dbfm_json(array('status' => FALSE, 'data' => 'move operation not permitted'));
734 }
735 } else {
736 dbfm_json(array('status' => FALSE, 'data' => 'insufficient params'));
737 }
738 exit();
739 break;
740
741 //Rename an existing file or directory
742 case "rename":
743 if(isset($_POST["param0"]) && isset($_POST["param1"])) {
744 $dest = trim(rawurldecode($_POST["param1"]));
745 $source = trim(rawurldecode($_POST["param0"]));
746 $ret = dbfm_rename($source, $dest, $err_arr);
747 dbfm_json(array('status' => $ret, 'data' => $err_arr));
748 if($ret && $dir) {
749 unset($_SESSION['tree_'.$root]);
750 }
751 }
752 else {
753 dbfm_json(array('status' => FALSE, 'data' => 'insufficient params'));
754 }
755 exit();
756 break;
757
758 //Read directory tree
759 case "readtree":
760 //Build dbfm directory tree
761 $tree = dbfm_tree($root_path);
762 dbfm_json(array('status' => TRUE, 'tree' => $tree, 'current' => $root_path));
763 exit();
764 break;
765
766 //Read directory set in $_POST["param0"]
767 case "read":
768 $rootpath_var = '';
769 // so what are we doing here? If we've got a session directory set, read it into variable read_dir then unset the session
770 // looks like the session setting takes precidence over any passed parameter ANYWAY, we end up setting read_dir
771 // why do we unset the session variable? - I suppose its going to be set again in just a mo
772 if(isset($_SESSION['directory'])) {
773 $read_dir = $_SESSION['directory'];
774 unset($_SESSION['directory']);
775 }
776 else if(isset($_POST["param0"])) {
777 $read_dir = rawurldecode($_POST["param0"]);
778 }
779 //to save posting back the upload directory and messing with hidden fields on the form
780 //I'm going to use a session variable (which is continually updated every time the user changes directory
781 $_SESSION['upload_dir'] = $read_dir;
782 $source = trim($read_dir);
783 $rootpath_var = 'dbfm_root_dir';
784
785 //code common to both, no error handling - ZZZZZZZZZZZZZZZdouble check on db_check
786 $dirlist = new dbfm_build_dir_list($source, $rootpath_var);
787 if($dirlist->get_breadcrumb()) {
788 dbfm_json(array('status' => TRUE, 'current' => $source, 'bcrumb' => $dirlist->get_breadcrumb(), 'dirs' => $dirlist->get_dir_listing(), 'files' => $dirlist->get_file_listing()));
789 }
790 else {
791 //invalid directory
792 dbfm_json(array('status' => FALSE, 'data' => 'invalid dir'));
793 }
794 exit(); // why do we need an exit?????
795 break;
796
797 //Search current directory for filename - ZZZZ haven't tackled search yet
798 //at the moment the search ignores the database and just searches through the directories
799 //what I need is something that can actualy search through the file CONTENT or keywords associated with the files
800 case "search":
801 if(isset($_POST["param0"]) && isset($_POST["param1"])) {
802 $source = trim(rawurldecode($_POST["param0"]));
803 $searchpattern = trim(rawurldecode($_POST["param1"]));
804 if ($searchpattern != "") {
805 $regexpsearch = '';
806 $maxlevel = 0;
807 @clearstatcache();
808 $search = new dbfm_searchFiles($source, $searchpattern, $maxlevel, $regexpsearch);
809 dbfm_json(array('files' => $search->get_files()));
810 }
811 } else {
812 dbfm_json(array('status' => FALSE, 'data' => 'insufficient params'));
813 }
814 exit();
815 break;
816
817 //Get file metadata - ZZZZ haven't tackled this yet
818 case "getmeta":
819 // the JS passes us the file ID of the entry
820 if(isset($_POST["param0"])) {
821 $fid = rawurldecode($_POST["param0"]);
822 if(($meta = dbfm_selected_file_record($fid)) !== FALSE) {
823 // we've loaded the contents of a file record into an array - perhaps the JS end doesn't like the fact we've
824 // included fields it doesn't know about
825 dbfm_json(array('status' => TRUE, 'meta' => $meta));
826 } else {
827 dbfm_json(array('status' => FALSE, 'data' => 'file record not found'));
828 }
829 } else {
830 dbfm_json(array('status' => FALSE, 'data' => 'insufficient params'));
831 }
832 exit();
833 break;
834
835 //Change file metadata - ZZZZ haven't tackled this yet - needs to pass the error array down to putmeta
836 case "putmeta":
837 if(isset($_POST["param0"]) && isset($_POST["param1"])) {
838 dbfm_json(array('status' => dbfm_putmeta(rawurldecode($_POST["param0"]), rawurldecode($_POST["param1"]))));
839 } else {
840 dbfm_json(array('status' => FALSE, 'data' => 'unknown action'));
841 }
842 exit();
843 break;
844
845 //I've added in all the dbfm_image stuff - s'neater that way rather than bothering with a seperate module
846 case 'get resize menu items':
847 $sizes = _dbfm_get_sizes();
848 $arraylen = count($sizes);
849 for ($i = 0; $i < $arraylen; $i++) {
850 $menus[] = $sizes[$i]['label'];
851 }
852 print dbfm_json($menus); //$menus;
853 break;
854
855 case 'preview image':
856 // this should all still work - dbfm send will decode the blob to a file and delete it once used
857 //this is STUPID code - dbfm should just be sending back the fid NOT the filepath
858 if($fid = dbfm_get_fid(trim(rawurldecode($_POST["filepath"])))){
859 $url = url('dbfm_send/' . $fid);
860 print $url;
861 }
862 else {
863 $modulepath = drupal_get_path('module', 'dbfm');
864 print($modulepath .'/image/no-preview.png');
865 }
866 break;
867
868 case strstr($var, 'resize to '):
869 //first check if we should operate on this file (i.e. one that is in the database)
870 if($fid = dbfm_get_fid(trim(rawurldecode($_POST["filepath"])))){
871 $file = dbfm_get_file_record($fid); //get a file record
872 $dir = dirname($file->fpath); //get the directory
873 $variable = str_replace('resize to ', '', $var); //which resize operation are we doing
874 $prefix = str_replace(' ', '_', $variable); //pepare the variable to be used as a file prefix
875 $filename = strrev(substr(strrev($file->fpath), 0, strpos(strrev($file->fpath), '/')));
876 $path = $dir .'/'. $prefix. '_'. $filename; //prepare a path+filename for the file we are going to create
877 $sizes = _dbfm_get_sizes();
878
879 foreach ($sizes as $key => $value){
880 if($value['label'] == $variable){
881 $height = $value['height'];
882 $width = $value['width'];
883 }
884 }
885 //this invokes the image toolkit to make a new resized FILE to use this for blobs we need to
886 //give it a temporary filename then ship that into the database making an appropriate database
887 //entry for it (using the $path already constructed)
888 //MUST test the image size and not allow an upsize. The image module complains LOUDLY if this
889 //happens
890 if (@image_scale($file->fpath, $path, $width, $height)){ //create our new file
891 $err = array();
892 dbfm_insert_file($path, $err); //add it to the database
893 print t($var .' complete');
894 }
895 else {
896 print t('Operation Failed: Target dimensions are larger than source dimensions');
897 }
898 }
899 break;
900 default:
901 dbfm_json(array('status' => FALSE, 'data' => 'illegal operation'));
902 exit();
903 break;
904 }
905 //should never get here.
906 exit();
907 }
908 exit();
909 }
910
911 /**
912 * Return data in JSON format.
913 *
914 * This function should be used for JavaScript callback functions returning
915 * data in JSON format. It sets the header for JavaScript output.
916 *
917 * @param $var
918 * (optional) If set, the variable will be converted to JSON and output.
919 */
920 function dbfm_json($var = NULL) {
921 // We are returning JavaScript, so tell the browser.
922 drupal_set_header('Content-Type: text/javascript; charset=utf-8');
923
924 if (isset($var)) {
925 echo drupal_to_js($var);
926 }
927 }
928
929 /**
930 * Main file manager function
931 */
932 function dbfm_main () {
933 global $base_url;
934
935 //users can optionally supply either a path or an fid as a parameter
936 //fid's are a single argument so lets start by counting what we've been given
937 $numargs = func_num_args();
938 if ($numargs > 0){
939 if ($numargs == 1) {
940 //it's probably an fid, let's check it's numeric, if not we'll give up and ignore it
941 //a single argument would always be too short for a directory path
942 $firstarg = func_get_arg(0);
943 if (is_numeric($firstarg)) {
944 // lets check that the number is a valid file ID
945 $fidquery = db_query("SELECT * FROM {dbfm_file} WHERE fid = '%d'",$firstarg);
946 $numret = db_num_rows($fidquery);
947 if ($numret != 1) {
948 drupal_set_message("Passed an Invalid Directory ID - " . $firstarg);
949 }
950 else {
951 //assuming it did bring back a record it could have been a file rather than a directory - lets take a look
952 //if it is a file we can go to the directory containing the file (the parent fid)
953 $fid_rec = db_fetch_object($fidquery);
954 if ($fid_rec-> fmime != 'directory') {
955 //we'll have to look one level up
956 $fidquery = db_query("SELECT * FROM {dbfm_file} WHERE fid = '%d'",$fid_rec->fparent);
957 //we're bound to have a record - and it MUST be a directory so ...
958 $fid_rec = db_fetch_object($fidquery);
959 }
960 $_SESSION['directory'] = $fid_rec-> fpath;
961 }
962 }
963 }
964 else {
965 $pathin = 'files';
966 //collect together the arguments and put them back together as a directory path
967 $arg_list = func_get_args();
968 for ($i = 0; $i < $numargs; $i++) {
969 if ($i == 0) {
970 //users won't know anything about the files directory
971 if ($arg_list[$i] != 'files') {
972 $pathin .= '/' . $arg_list[$i];
973 }
974 }
975 else {
976 $pathin .= '/' . $arg_list[$i];
977 }
978 }
979 //now we've collected things into a path we'll see if there's a database record that matches
980 $pathquery = db_query("SELECT * FROM {dbfm_file} WHERE fpath = '%s'",$pathin);
981 $numret = db_num_rows($pathquery);
982 if ($numret != 1) {
983 //I suppose I could help them out with a LIKE "%path" but it's not straightforward because I'd have to strip off 'files'
984 drupal_set_message("Invalid Directory path - " . $pathin);
985 }
986 //check it's a directory and not a file
987 $path_rec = db_fetch_object($pathquery);
988 if ($path_rec->fmime != 'directory') {
989 //go up a directory
990 $pathquery = db_query("SELECT * FROM {dbfm_file} WHERE fid = '%d'",$path_rec->fparent);
991 $path_rec = db_fetch_object($pathquery);
992 }
993 $_SESSION['directory'] = $path_rec->fpath;
994 }
995 }
996
997
998 //force the tree to be re-read
999 $root = file_directory_path().variable_get('dbfm_root_dir', '');
1000 unset($_SESSION['tree_'.$root]);
1001
1002 dbfm_include();
1003
1004 //this calls ALL modules that have the hook dbfm_extend_js and collects the results to gether to act on them
1005 module_invoke_all('dbfm_extend_js');
1006
1007 if (is_null($inline_js)) {
1008 $clean_url = variable_get('clean_url', 0);
1009 $clean = (($clean_url == 0) || ($clean_url == '0')) ? FALSE : TRUE;
1010 //inline_js ends up filled with JS to insert into the form. drupal_set_html_head actually adds it
1011 $inline_js = dbfm_inline_js($base_url, $clean);
1012 }
1013
1014 $output = '<noscript><p class="err">JavaScript must be enabled in order to use dbfm!</p></noscript>'."\n";
1015 //this is where we add the upload form stuff to which everything else is attached
1016 $output .= '<div id="dbfm">'."\n";
1017 //no longer need to put the upload form on the main page
1018 // $output .= drupal_get_form('dbfm_upload_fieldset');
1019 $output .= '</div>'."\n";
1020 return $output;
1021 }
1022
1023 /**
1024 * popup form constructor
1025 */
1026 function dbfm_attachit() {
1027 global $base_url;
1028
1029 // add some javascript
1030 if (is_null($inline_js)) {
1031 $clean_url = variable_get('clean_url', 0);
1032 $clean = (($clean_url == 0) || ($clean_url == '0')) ? FALSE : TRUE;
1033 $inline_js = dbfm_inline_js($base_url, $clean);
1034 }
1035
1036 //bung all the javascript and css details in the header
1037 $modulepath = drupal_get_path('module', 'dbfm');
1038 $jspath = $modulepath .'/js/dbfm.js';
1039 $stylepath = $modulepath .'/css/dbfm.css';
1040 $modulepath = drupal_get_path('module', 'greybox');
1041 $greypath = $modulepath .'/greybox.js'; //try a completely different js file - we may not need it
1042 $greystyle = $modulepath .'/greybox.css';
1043 $jsjq = 'misc/jquery.js';
1044 $jsdrup = 'misc/drupal.js';
1045
1046 $output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN">'."\n";
1047 $output .= "<html>\n";
1048 $output .= "<head>\n";
1049 $output .= "<title>dbFM File Browser</title>\n";
1050 $output .= "<link href=\"$stylepath\" rel=\"stylesheet\" type=\"text/css\">";
1051 $output .= "<link href=\"$greystyle\" rel=\"stylesheet\" type=\"text/css\">";
1052 $output .= "<script type=\"text/javascript\" src=\"$jsjq\"></script>\n";
1053 $output .= "<script type=\"text/javascript\" src=\"$jsdrup\"></script>\n";
1054 $output .= "<script type=\"text/javascript\" src=\"$jspath\"></script>\n";
1055 $output .= "<script type=\"text/javascript\" src=\"$greypath\"></script>\n";
1056 $output .= $inline_js;
1057 $output .= "</head>\n\n";
1058 $output .= "<body><p>Select the file you want to link or embed using the File Browser, then use the context menu (right click)</p>\n";
1059 $output .= '<div id="dbfm-popup">'."\n"; //put in the placeholder for the dbfm browser
1060 $output .= '</div>'."\n";
1061 $output .= "</body>";
1062 $output .= "</html>\n";
1063 print $output;
1064
1065 }
1066
1067 /**
1068 * popup form constructor
1069 */
1070 function dbfm_searchit() {
1071 global $base_url;
1072
1073 $output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN">'."\n";
1074 $output .= "<html>\n";
1075 $output .= "<head>\n";
1076 $output .= "<title>dbFM Search Window</title>\n";
1077 $output .= "</head>\n\n";
1078 $output .= "<body><p>Find what you're looking for here</p>\n";
1079 $output .= "</body>";
1080 $output .= "</html>\n";
1081 print $output;
1082
1083 }
1084
1085 /**
1086 * popup form constructor for the help screen
1087 */
1088 function dbfm_helpit() {
1089 global $base_url;
1090
1091 $output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN">'."\n";
1092 $output .= "<html>\n";
1093 $output .= "<head>\n";
1094 $output .= "<title>dbFM Help Window</title>\n";
1095 $output .= "</head>\n\n";
1096 $output .= "<body><p>Initially this will just display the version information, in the longer term a tabbed window with help</p>\n";
1097 $output .= "</body>";
1098 $output .= "</html>\n";
1099 print $output;
1100
1101 }
1102
1103 /**
1104 * popup form constructor for the file upload screen
1105 */
1106 function dbfm_uploadit() {
1107 global $base_url;
1108
1109 $output1 .= '<div id="dbfm_upload">'."\n";
1110 $output1 .= drupal_get_form('dbfm_upload_fieldset');
1111 $output1 .= '</div>'."\n";
1112
1113 // add some javascript - I need to split the javascript file - it's pointless adding all this to a document when only a tiny bit of code is needed
1114 // jsut what is needed??
1115 if (is_null($inline_js)) {
1116 $clean_url = variable_get('clean_url', 0);
1117 $clean = (($clean_url == 0) || ($clean_url == '0')) ? FALSE : TRUE;
1118 $inline_js = dbfm_inline_js($base_url, $clean);
1119 }
1120
1121 //bung all the javascript and css details in the header
1122 //zzzzz again - we don't need the whole dbfm.js, what do we need?
1123 //We need to find out the current path on screen - that could be passed in the url?
1124 //having passed it in the url we could pass it to / put it into the upload fieldset?
1125 //what else do we need?? where's the upload js invoked?
1126 $modulepath = drupal_get_path('module', 'dbfm');
1127 $jspath = $modulepath .'/js/upjava.js'; //I've made a cut-down js file with the minimum included
1128 $stylepath = $modulepath .'/css/upjava.css';
1129 $jsjq = 'misc/jquery.js';
1130 $jsdrup = 'misc/drupal.js';
1131
1132 $output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN">'."\n";
1133 $output .= "<html>\n";
1134 $output .= "<head>\n";
1135 $output .= "<title>dbFM File Upload</title>\n";
1136 $output .= "<link href=\"$stylepath\" rel=\"stylesheet\" type=\"text/css\">";
1137 $output .= "<script type=\"text/javascript\" src=\"$jsjq\"></script>\n";
1138 $output .= "<script type=\"text/javascript\" src=\"$jsdrup\"></script>\n";
1139 $output .= "<script type=\"text/javascript\" src=\"$jspath\"></script>\n";
1140 $output .= $inline_js;
1141 $output .= "</head>\n\n";
1142 $output .= "<body>\n";
1143 $output .= '<div id="progress"><img src="' . variable_get('dbfm_icon_dir','') . '/progress.gif" alt= "Working"></div>';
1144 $output .= $output1;
1145 $output .= "</body>";
1146 $output .= "</html>\n";
1147 print $output;
1148 }
1149
1150
1151 /**
1152 * popup form constructor for file properties this is called when the user presses the properties icon
1153 * in the file browser
1154 */
1155 function dbfm_propertit() {
1156 global $base_url;
1157
1158 $output = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN">'."\n";
1159 $output .= "<html>\n";
1160 $output .= "<head>\n";
1161 $output .= "<title>dbFM File Properties</title>\n";
1162 $output .= "</head>\n\n";
1163 $output .= "<body><p>This will allow you to display and edit the file and directory properties</p>\n";
1164 //insert the drupal form here - I don't believe I have anything to respond to a submit - I'll look at