/[drupal]/contributions/modules/auditfiles/references.admin.inc
ViewVC logotype

Contents of /contributions/modules/auditfiles/references.admin.inc

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


Revision 1.1 - (show annotations) (download) (as text)
Wed Jun 3 22:53:23 2009 UTC (5 months, 3 weeks ago) by mikeryan
Branch: MAIN
CVS Tags: HEAD
File MIME type: text/x-php
#185904 by mikeryan - Add several new features
1 <?php
2 // $Id: notindb.admin.inc,v 1.1 2007/12/05 22:33:19 stuartgreenfield Exp $
3
4 /**
5 * @file
6 * Callback and functions to generate references report
7 */
8
9
10 /**
11 * Menu callback: audit files referenced but not attached via uploads
12 */
13 function auditfiles_references() {
14 return drupal_get_form('auditfiles_references_form');
15 }
16
17 /**
18 * Form definition for audit files not in database
19 */
20 function auditfiles_references_form(&$form_state) {
21 // drupal_set_message("form: form_state: ".dpr($form_state,TRUE));
22 if (isset($form_state['storage']['confirm'])) {
23 return auditfiles_references_form_confirm($form_state);
24 }
25 // Action button
26 $form['options'] = array(
27 '#type' => 'fieldset',
28 '#title' => t('Action'),
29 '#prefix' => '<div class="container-inline">',
30 '#suffix' => '</div>',
31 );
32
33 $options = array(
34 'donothing' => t('Do nothing'),
35 'delete' => t('Delete selected files'),
36 'attach' => t('Attach selected files'),
37 'attachunique' => t('Attach all unique matches'),
38 );
39
40 $form['options']['operation'] = array(
41 '#type' => 'select',
42 '#options' => $options,
43 '#default_value' => 'donothing',
44 );
45
46 $form['options']['submit'] = array(
47 '#type' => 'submit',
48 '#value' => t('Update'),
49 );
50
51 // Process each result in turn and build check box list
52 // Note we cut down the overhead by preselecting nodes with potential
53 // to match the $patterns below
54 $result = db_query("SELECT n.nid,n.title,nr.body
55 FROM {node} n
56 INNER JOIN {node_revisions} nr ON n.vid=nr.vid
57 where nr.body like '%img%' or nr.body like '%window.open%'
58 or nr.body like '%href%'
59 ORDER BY n.nid");
60
61 // Start at 1 - $files checkboxes shouldn't have a 0 key
62 $matchid = 1;
63 $files = array();
64 $singlematch = 0;
65 $multmatch = 0;
66 $nomatch = 0;
67 $filedirpath = file_directory_path();
68 $domains = explode(' ', variable_get('auditfiles_include_domains', ''));
69 $externaldomains = array();
70
71 $patterns = array(
72 // Get src attributes from img tags (assumes ")
73 '(?:<img [^>]*src[ ]*=[ ]*"([^"]*)")',
74 // Get href attributes from a tags (assumes ")
75 '(?:<a [^>]*href[ ]*=[ ]*"([^"]*)")',
76 // Get window.open argument (assumes ')
77 "(?:window.open[ ]*\([ ]*'([^\']*)')",
78 );
79 $regpatt = '/'.implode('|', $patterns).'/';
80
81 // Stuff not likely to represent local file references
82 $ignorepatterns = array(
83 'window\.open',
84 '^mailto:',
85 '\.html?($|\?)',
86 '^#',
87 '^javascript:void\(0\)',
88 '^ftp:\/\/',
89 );
90 // Add references to our own home page(s)
91 foreach ($domains as $domain) {
92 $ignorepatterns[] = "^https?:\/\/$domain\/?$";
93 }
94 $ignorepatt = '/'.implode('|', $ignorepatterns).'/';
95
96 while ($node = db_fetch_object($result)) {
97 $nodelink = l($node->title, 'node/'.$node->nid);
98
99 $imgsmatched = preg_match_all($regpatt, $node->body, $imgmatchgroups);
100
101 // Pull all matches together
102 $imgmatches = array();
103 for ($i = 1; $i < count($patterns)+1; $i++) {
104 $imgmatches = array_merge($imgmatches, $imgmatchgroups[$i]);
105 }
106
107 for ($i=0; $i < count($imgmatches); $i++) {
108 $src = trim($imgmatches[$i]);
109 // Merge gives us some blanks
110 if (!$src) continue;
111 // Bunch of stuff that won't get us anywhere
112 if (preg_match($ignorepatt, $src)) continue;
113
114 // If we've got a full URL, and the domain is not in our list of "local"
115 // domains, assume it's a valid external URL and leave it be
116 $domainfound = preg_match('&^https?://([^/$]+)&', $src, $matches);
117 if (!$domainfound) {
118 $local = TRUE;
119 } else {
120 $local = FALSE;
121 $srcdomain = $matches[1];
122 foreach ($domains as $domain) {
123 if ($domain == $srcdomain) {
124 $local = TRUE;
125 break;
126 }
127 }
128 }
129 if (!$local) {
130 $externaldomains[$srcdomain]++;
131 continue;
132 }
133
134 // Fix up encoded spaces
135 $decodesrc = str_replace('%20', ' ', $src);
136
137 // If we've got an exact match on path, and have an exact match on that
138 // path in the {upload} table, we don't have to go farther (note how we
139 // skip the / in the src)
140 $hit = db_result(db_query("SELECT u.nid
141 FROM {files} f
142 INNER JOIN {upload} u ON f.fid=u.fid
143 WHERE u.nid=%d AND CONCAT('/', f.filepath)='%s'",
144 $node->nid, $decodesrc));
145
146 if (!$hit) {
147 $basename = basename($src);
148 $decodebase = basename($decodesrc);
149 $fileresult = db_query("SELECT f.fid,f.filepath,u.nid
150 FROM {files} f
151 LEFT JOIN {upload} u ON f.fid=u.fid AND u.nid=%d
152 WHERE f.filename='%s'",
153 $node->nid, $decodebase);
154 $nummatches = 0;
155 while ($file = db_fetch_object($fileresult)) {
156 $nummatches++;
157 // Visible fields first
158 $form['titles'][$matchid] = array('#value' => $nodelink);
159 $form['srcs'][$matchid] = array('#value' => $src);
160 $form['fids'][$matchid] = array('#value' => $file->fid);
161 // Strip the Drupal file path, and make the link
162 $filepath = preg_replace('@^'.preg_quote($filedirpath).'/@', '', $file->filepath);
163 $filelink = l($filepath, $GLOBALS['base_url'] .'/'. $filedirpath .'/'.
164 str_replace('\\', '/', $filepath));
165 $form['paths'][$matchid] = array('#value' => $filelink);
166 $files[$matchid] = '';
167 // Fields passed through form submission
168 $form['nidvals'][$matchid] = array('#type' => 'value', '#value' => $node->nid);
169 $form['srcvals'][$matchid] = array('#type' => 'value', '#value' => $src);
170 $form['fidvals'][$matchid] = array('#type' => 'value', '#value' => $file->fid);
171 $form['pathvals'][$matchid] = array('#type' => 'value', '#value' => $file->filepath);
172 if (!$file->nid) {
173 $form['noupload'][$matchid] = array('#type' => 'value', '#value' => TRUE);
174 }
175 $matchid++;
176 }
177 if ($nummatches == 0) {
178 $nomatch++;
179 $form['titles'][$matchid] = array('#value' => $nodelink);
180 $form['srcs'][$matchid] = array('#value' => $src);
181 $form['fids'][$matchid] = array('#value' => '');
182 $form['paths'][$matchid] = array('#value' => '');
183 $files[$matchid] = '';
184 $form['nidvals'][$matchid] = array('#type' => 'value', '#value' => $node->nid);
185 $form['srcvals'][$matchid] = array('#type' => 'value', '#value' => $src);
186 $form['noupload'][$matchid] = array('#type' => 'value', '#value' => TRUE);
187 $matchid++;
188 } elseif ($nummatches == 1) {
189 $singlematch++;
190 $form['unique'][$matchid-1] = array('#type' => 'value', '#value' => TRUE);
191 } else {
192 $multmatch++;
193 }
194 }
195 }
196 }
197
198 if (count($externaldomains) > 0) {
199 $form['externaldomains'] = array(
200 '#type' => 'fieldset',
201 '#title' => 'External domains referenced',
202 '#collapsible' => TRUE,
203 '#collapsed' => TRUE,
204 );
205
206 arsort($externaldomains);
207
208 foreach ($externaldomains as $domain => $count) {
209 $form['domains'][$domain] = array('#value' => $domain);
210 $form['domaincounts'][$domain] = array('#value' => $count);
211 }
212 }
213
214 // Remember, we started at 1 instead of 0...
215 if ($matchid > 1) {
216 $broken = $nomatch + $singlematch + $multmatch;
217 $total = format_plural($broken, '1 broken reference found:', '@count broken references found:');
218 $unmatched = "$nomatch with no matches";
219 $uniquematch = "$singlematch with a unique match";
220 $multmatches = "$multmatch with multiple matches";
221 $form['count'] = array(
222 '#value' => "<div>$total<br />$unmatched<br />$uniquematch<br />$multmatches</div>",
223 );
224 }
225 else {
226 $form['count'] = array(
227 '#value' => t('No broken references found.'),
228 );
229 }
230
231 // Add list of files to checkboxes
232 $form['files'] = array('#type' => 'checkboxes', '#options' => $files);
233
234 // Maintains hidden fields
235 $form['#tree'] = TRUE;
236
237 // Return form
238 return $form;
239 }
240
241 /**
242 * Theme auditfiles_references_form
243 */
244 function theme_auditfiles_references_form($form) {
245 // Render count
246 $output = drupal_render($form['count']);
247
248 // List any external domain references found
249 if (isset($form['domains']) && is_array($form['domains'])) {
250 $header = array(
251 array('data' => t('External Domain')),
252 array('data' => t('# References')),
253 );
254 foreach (element_children($form['domains']) as $key) {
255 $row = array();
256 $row[] = drupal_render($form['domains'][$key]);
257 $row[] = drupal_render($form['domaincounts'][$key]);
258 $rows[] = $row;
259 }
260
261 // Render themed table
262 $tableoutput = theme('table', $header, $rows);
263 $form['externaldomains']['list'] = array('#value' => $tableoutput);
264 $output .= drupal_render($form['externaldomains']);
265 }
266
267 // If there are files found
268 if (isset($form['titles']) && is_array($form['titles'])) {
269 // Render actions
270 $output .= drupal_render($form['options']);
271
272 // Construct table of files
273 $header = array(
274 t('Select'),
275 t('Node'),
276 t('Src'),
277 t('Fid'),
278 t('Path'),
279 );
280
281 $rows = array();
282 foreach (element_children($form['titles']) as $key) {
283 $row = array();
284 $row[] = drupal_render($form['files'][$key]);
285 $row[] = drupal_render($form['titles'][$key]);
286 $row[] = drupal_render($form['srcs'][$key]);
287 $row[] = drupal_render($form['fids'][$key]);
288 $row[] = drupal_render($form['paths'][$key]);
289 $rows[] = $row;
290 }
291
292 // Render themed table
293 $output .= theme('table', $header, $rows);
294 }
295 $output .= drupal_render($form);
296 // Return output
297 return $output;
298 }
299
300 function auditfiles_references_form_submit($form, &$form_state) {
301 // drupal_set_message("submit form_state: ".dpr($form_state, TRUE));
302 if ($form_state['clicked_button']['#id'] == 'edit-options-submit' &&
303 $form_state['values']['options']['operation'] <> 'donothing') {
304 $form_state['storage']['confirm'] = TRUE;
305 $form_state['storage']['values'] = $form_state['values'];
306 }
307 }
308
309 function auditfiles_references_form_confirm(&$form_state) {
310 // drupal_set_message("form_confirm: values: ".dpr($values, TRUE));
311 $values = $form_state['storage']['values'];
312 $operation = $values['options']['operation'];
313 switch ($operation) {
314 case 'delete':
315 $optype = 'delete';
316 $seltype = 'selected';
317 break;
318 case 'attach':
319 $optype = 'attach';
320 $seltype = 'selected';
321 break;
322 case 'attachunique':
323 $optype = 'attach';
324 $seltype = 'unique';
325 break;
326 case 'donothing':
327 default:
328 return;
329 }
330
331 $form['changelist'] = array('#prefix' => '<ul>', '#suffix' => '</ul>', '#tree' => TRUE);
332
333 // Note we iterate over fidvals, since no operation makes sense without a valid file
334 $count = 0;
335 foreach ($values['fidvals'] as $id => $value) {
336 if (($seltype == 'unique' && $values['unique'][$id]) ||
337 ($seltype == 'selected' && $values['files'][$id] == $id)) {
338 $count++;
339 // Limit what's displayed (also helps avoid max_allowed_packet errors)
340 if ($count == 50) {
341 $message = '...and many more...';
342 } elseif ($count < 50) {
343 if ($optype == 'delete') {
344 $message = "Deleting file <strong>".$values['pathvals'][$id].'</strong>';
345 } else {
346 $message = 'Replacing src <strong>'.$values['srcvals'][$id].'</strong> with <strong>'.
347 $values['pathvals'][$id].'</strong> for node rev <strong>'.$values['nidvals'][$id].
348 '</strong>';
349 }
350 }
351 if ($message) {
352 $form['changelist'][$id] = array('#type' => 'hidden', '#value' => $message,
353 '#prefix' => '<li>', '#suffix' => $message ."</li>\n");
354 unset($message);
355 }
356 } else {
357 // Unsetting the unprocessed fidvals prevents confirm_submit from dealing with them
358 unset($form_state['storage']['values']['fidvals'][$id]);
359 }
360 }
361 $form['operation'] = array('#type' => 'hidden', '#value' => $operation);
362 $form['#submit'][] = 'auditfiles_references_form_confirm_submit';
363
364 return confirm_form(
365 $form,
366 t('Are you sure you want to make these changes?'),
367 'admin/reports/auditfiles/references',
368 '<strong>'. t('This action cannot be undone.') .'</strong>',
369 t('Process all'),
370 t('Cancel')
371 );
372 }
373
374 function auditfiles_references_form_confirm_submit($form, &$form_state) {
375 // drupal_set_message('confirm_submit, form: '.dpr($form, TRUE));
376 // drupal_set_message('confirm_submit, form_state: '.dpr($form_state, TRUE));
377 if ($form_state['values']['confirm']) {
378 $values = $form_state['storage']['values'];
379 //drupal_set_message("in confirm_submit, values: ".dpr($values,TRUE));
380 foreach ($values['fidvals'] as $id => $fid) {
381 if ($values['options']['operation'] == 'delete') {
382 db_query("DELETE FROM {files}
383 WHERE fid=%d",
384 $fid);
385 if (file_delete(file_create_path($values['pathvals'][$id]))) {
386 drupal_set_message(t('%file was deleted', array('%file' => $values['pathvals'][$id])));
387 }
388 else {
389 drupal_set_message(t('Failed to delete %file', array('%file' => $values['pathvals'][$id])));
390 }
391 } else {
392 // Load $values['nidvals'][$id], replace srcvals with pathvals, save
393 // If necessary, write record to {upload} table
394 $newpath = '/'.$values['pathvals'][$id];
395 $oldpath = $values['srcvals'][$id];
396
397 if ($newpath != $oldpath) {
398 $row = db_fetch_object(db_query("SELECT nr.body,nr.vid
399 FROM {node_revisions} nr
400 INNER JOIN {node} n ON nr.vid=n.vid
401 WHERE n.nid = %d",
402 $values['nidvals'][$id]));
403 $body = str_replace($oldpath, $newpath, $row->body);
404 db_query("UPDATE {node_revisions}
405 SET body='%s'
406 WHERE vid=%d",
407 $body, $row->vid);
408 }
409 if ($values['noupload'][$id]) {
410 db_query("INSERT INTO {upload}
411 (fid, nid, vid, description, list, weight)
412 SELECT %d, n.nid, n.vid, 'Attached by auditfiles', 0, 0
413 FROM {node} n
414 WHERE n.nid=%d",
415 $fid, $values['nidvals'][$id]);
416 }
417 drupal_set_message("Updated path $oldpath to $newpath for rev ".$values['nidvals'][$id]);
418 }
419 }
420 // Clear so our return to the primary form doesn't think we're going to the confirmation form
421 unset($form_state['storage']['confirm']);
422 }
423 }

  ViewVC Help
Powered by ViewVC 1.1.2