]> git.mjollnir.org Git - moodle.git/commitdiff
Centralised file upload code, integration with clam AV, integration with some modules...
authormjollnir_ <mjollnir_>
Tue, 14 Sep 2004 22:58:13 +0000 (22:58 +0000)
committermjollnir_ <mjollnir_>
Tue, 14 Sep 2004 22:58:13 +0000 (22:58 +0000)
These patches are maintained in an publicly accessible Arch repository, see: http://lists.eduforge.org/cgi-bin/archzoom.cgi/arch-eduforge@catalyst.net.nz--2004-MIRROR/moodle--eduforge--1.3.3

Index of arch patches in this commit:

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-15
    final touches to sears stuff until testing can begin, beginning of magical uploadey wrappery function goodness

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-18
    Virus scanning on upload

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-19
    made emacs use spaces instead of tabs and fixed lib/moodlelib.php where it was bad in the new functions; few wording changes, added in support for clamdscan

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-20
    handlevirus.php = new script to handle output of clamscan (designed for cron clamscan), changes to strings for emailing out virus notifications, changes to moodlelib - slightly different notice reporting in handle_infected_file and new function for replacing file with message

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-21
    refactor to filter out invalid lines in input to handlevirus

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-22
    modified assignment to use hande_file_upload

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-25
    bug fix for handle_file_upload

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-26
    Small fix for non thinking brain doing something silly

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-35
    small fix to switch order of items in drop down to allow sensible defaults

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-36
    small changes to strings file

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-38
    taken stuff out of moodlelib to put in upload class

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-39
    new upload class -in a changeset by itself just in case - not quite finished

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-40
    tweaks to upload class - clam_scan_file can now take a path as an argument, not just an entry from _FILES, there is better handling of failure and notification, more allowance for module writers to keep control in general. Also slightly nicer strings entries for a few things

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-41
    upload class integration with assignment module, bug fix, slight tweak

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-42
    small changes to uploadlib, integration with assessment and assignment

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-44
    tweaks for assessment and assignment for uploading

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-48
    integration with exercise module

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-49
    integration of virus stuff with forum module

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-50
    integration of upload class and glossary module

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-51
    just in case glossary_move_attachments is ever used, we change the log entries before we move the files. also  moved clam_log_upload out of the class

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-52
    virus scanning for imports for glossary

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-53
    relog entries when moving files attached to forum posts

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-54
    resource module integration with virus scanning

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-55
    scorm integration with upload/virus class

arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-56
    fix for handlevirus.php since upload class changes

Full logs:

Revision: moodle--eduforge--1.3.3--patch-15
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Wed Sep  1 17:28:13 NZST 2004
Standard-date: 2004-09-01 05:28:13 GMT
Modified-files: lang/en/moodle.php lib/moodlelib.php
    mod/assessment/sears.php mod/assessment/upload.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-15
Summary: final touches to sears stuff until testing can begin, beginning of magical uploadey wrappery function goodness
Keywords:

Revision: moodle--eduforge--1.3.3--patch-18
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Thu Sep  2 15:49:54 NZST 2004
Standard-date: 2004-09-02 03:49:54 GMT
Modified-files: admin/config.html lang/en/moodle.php
    lib/moodlelib.php mod/assessment/upload.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-18
Summary: Virus scanning on upload
Keywords:

Revision: moodle--eduforge--1.3.3--patch-19
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Thu Sep  2 17:06:14 NZST 2004
Standard-date: 2004-09-02 05:06:14 GMT
Modified-files: lang/en/moodle.php lib/moodlelib.php
    mod/assessment/upload.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-19
Summary: made emacs use spaces instead of tabs and fixed lib/moodlelib.php where it was bad in the new functions; few wording changes, added in support for clamdscan
Keywords:

Revision: moodle--eduforge--1.3.3--patch-20
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Fri Sep  3 16:06:05 NZST 2004
Standard-date: 2004-09-03 04:06:05 GMT
New-files: admin/.arch-ids/handlevirus.php.id
    admin/handlevirus.php
Modified-files: lang/en/moodle.php lib/moodlelib.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-20
Summary: handlevirus.php = new script to handle output of clamscan (designed for cron clamscan), changes to strings for emailing out virus notifications, changes to moodlelib - slightly different notice reporting in handle_infected_file and new function for replacing file with message
Keywords:

Revision: moodle--eduforge--1.3.3--patch-21
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Mon Sep  6 11:37:31 NZST 2004
Standard-date: 2004-09-05 23:37:31 GMT
Modified-files: admin/handlevirus.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-21
Summary: refactor to filter out invalid lines in input to handlevirus
Keywords:

Revision: moodle--eduforge--1.3.3--patch-22
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Mon Sep  6 13:07:48 NZST 2004
Standard-date: 2004-09-06 01:07:48 GMT
Modified-files: mod/assignment/upload.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-22
Summary: modified assignment to use hande_file_upload
Keywords:

Revision: moodle--eduforge--1.3.3--patch-25
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Mon Sep  6 16:32:11 NZST 2004
Standard-date: 2004-09-06 04:32:11 GMT
Modified-files: lib/moodlelib.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-25
Summary: bug fix for handle_file_upload
Keywords:

Revision: moodle--eduforge--1.3.3--patch-26
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Mon Sep  6 16:51:50 NZST 2004
Standard-date: 2004-09-06 04:51:50 GMT
Modified-files: lib/moodlelib.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-26
Summary: Small fix for non thinking brain doing something silly
Keywords:

Revision: moodle--eduforge--1.3.3--patch-35
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Fri Sep 10 10:09:53 NZST 2004
Standard-date: 2004-09-09 22:09:53 GMT
Modified-files: admin/config.html
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-35
Summary: small fix to switch order of items in drop down to allow sensible defaults
Keywords:

Revision: moodle--eduforge--1.3.3--patch-36
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Fri Sep 10 10:11:29 NZST 2004
Standard-date: 2004-09-09 22:11:29 GMT
Modified-files: lang/en/moodle.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-36
Summary: small changes to strings file
Keywords:

Revision: moodle--eduforge--1.3.3--patch-38
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Fri Sep 10 10:17:24 NZST 2004
Standard-date: 2004-09-09 22:17:24 GMT
Modified-files: lib/moodlelib.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-38
Summary: taken stuff out of moodlelib to put in upload class
Keywords:

Revision: moodle--eduforge--1.3.3--patch-39
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Fri Sep 10 10:21:21 NZST 2004
Standard-date: 2004-09-09 22:21:21 GMT
New-files: lib/.arch-ids/uploadlib.php.id lib/uploadlib.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-39
Summary: new upload class -in a changeset by itself just in case - not quite finished
Keywords:

Revision: moodle--eduforge--1.3.3--patch-40
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Fri Sep 10 11:58:24 NZST 2004
Standard-date: 2004-09-09 23:58:24 GMT
Modified-files: lang/en/moodle.php lib/uploadlib.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-40
Summary: tweaks to upload class - clam_scan_file can now take a path as an argument, not just an entry from _FILES, there is better handling of failure and notification, more allowance for module writers to keep control in general. Also slightly nicer strings entries for a few things
Keywords:

Revision: moodle--eduforge--1.3.3--patch-41
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Fri Sep 10 12:38:02 NZST 2004
Standard-date: 2004-09-10 00:38:02 GMT
Modified-files: lib/uploadlib.php mod/assignment/upload.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-41
Summary: upload class integration with assignment module, bug fix, slight tweak
Keywords:

Revision: moodle--eduforge--1.3.3--patch-42
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Fri Sep 10 15:30:20 NZST 2004
Standard-date: 2004-09-10 03:30:20 GMT
Modified-files: lib/uploadlib.php mod/assessment/upload.php
    mod/assessment/view.php mod/assignment/upload.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-42
Summary: small changes to uploadlib, integration with assessment and assignment
Keywords:

Revision: moodle--eduforge--1.3.3--patch-44
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Fri Sep 10 16:54:40 NZST 2004
Standard-date: 2004-09-10 04:54:40 GMT
Modified-files: mod/assessment/lib.php
    mod/assignment/lib.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-44
Summary: tweaks for assessment and assignment for uploading
Keywords:

Revision: moodle--eduforge--1.3.3--patch-48
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Mon Sep 13 09:57:03 NZST 2004
Standard-date: 2004-09-12 21:57:03 GMT
Modified-files: lang/en/moodle.php
    mod/exercise/locallib.php mod/exercise/upload.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-48
Summary: integration with exercise module
Keywords:

Revision: moodle--eduforge--1.3.3--patch-49
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Mon Sep 13 11:35:46 NZST 2004
Standard-date: 2004-09-12 23:35:46 GMT
Modified-files: mod/forum/lib.php mod/forum/post.html
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-49
Summary: integration of virus stuff with forum module
Keywords:

Revision: moodle--eduforge--1.3.3--patch-50
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Mon Sep 13 14:00:29 NZST 2004
Standard-date: 2004-09-13 02:00:29 GMT
Modified-files: lang/en/glossary.php mod/glossary/edit.html
    mod/glossary/edit.php mod/glossary/lib.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-50
Summary: integration of upload class and glossary module
Keywords:

Revision: moodle--eduforge--1.3.3--patch-51
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Mon Sep 13 15:13:02 NZST 2004
Standard-date: 2004-09-13 03:13:02 GMT
Modified-files: lib/uploadlib.php mod/glossary/lib.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-51
Summary: just in case glossary_move_attachments is ever used, we change the log entries before we move the files. also  moved clam_log_upload out of the class
Keywords:

Revision: moodle--eduforge--1.3.3--patch-52
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Mon Sep 13 15:26:56 NZST 2004
Standard-date: 2004-09-13 03:26:56 GMT
Modified-files: mod/glossary/import.html
    mod/glossary/import.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-52
Summary: virus scanning for imports for glossary
Keywords:

Revision: moodle--eduforge--1.3.3--patch-53
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Mon Sep 13 16:02:22 NZST 2004
Standard-date: 2004-09-13 04:02:22 GMT
Modified-files: mod/forum/lib.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-53
Summary: relog entries when moving files attached to forum posts
Keywords:

Revision: moodle--eduforge--1.3.3--patch-54
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Mon Sep 13 16:58:37 NZST 2004
Standard-date: 2004-09-13 04:58:37 GMT
Modified-files: mod/resource/coursefiles.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-54
Summary: resource module integration with virus scanning
Keywords:

Revision: moodle--eduforge--1.3.3--patch-55
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Tue Sep 14 16:15:47 NZST 2004
Standard-date: 2004-09-14 04:15:47 GMT
Modified-files: mod/scorm/coursefiles.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-55
Summary: scorm integration with upload/virus class
Keywords:

Revision: moodle--eduforge--1.3.3--patch-56
Archive: arch-eduforge@catalyst.net.nz--2004
Creator: Penny Leach <penny@catalyst.net.nz>
Date: Wed Sep 15 10:33:23 NZST 2004
Standard-date: 2004-09-14 22:33:23 GMT
Modified-files: admin/handlevirus.php
New-patches: arch-eduforge@catalyst.net.nz--2004/moodle--eduforge--1.3.3--patch-56
Summary: fix for handlevirus.php since upload class changes
Keywords:

18 files changed:
admin/config.html
admin/handlevirus.php [new file with mode: 0644]
lang/en/glossary.php
lang/en/moodle.php
lib/uploadlib.php [new file with mode: 0644]
mod/assignment/lib.php
mod/assignment/upload.php
mod/exercise/locallib.php
mod/exercise/upload.php
mod/forum/lib.php
mod/forum/post.html
mod/glossary/edit.html
mod/glossary/edit.php
mod/glossary/import.html
mod/glossary/import.php
mod/glossary/lib.php
mod/resource/coursefiles.php
mod/scorm/coursefiles.php

index f642c1c3f354325b9f4bd82c35a866574d9a8c6c..18bbaad5e83a418bd18458644313f65f7e1b1ad5 100644 (file)
     <?php print_string("configmaxbytes") ?>
     </td>
 </tr>
+<tr valign=top>
+    <td align=right><p>runclamonupload:</p></td>
+    <td>
+    <?php
+      unset($options);
+      $options[0] = get_string("no");
+      $options[1] = get_string("yes");
+      
+      choose_from_menu($options,"runclamonupload",$config->runclamonupload,"","","");
+      ?>
+      </td>
+      <td><?php print_string("configrunclamonupload") ?></td>
+</tr>
+<tr valign=top>
+    <td align=right><p>pathtoclam:</p></td>
+    <td><input type="text" name="pathtoclam" size="30" value="<?php echo $config->pathtoclam ?>" /></td>
+    <td><?php print_string("configpathtoclam") ?></td>
+</tr>
+<tr valign=top>
+    <td align=right><p>quarantinedir:</p></td>
+    <td><input type="text" name="quarantinedir" size="30" value="<?php echo $config->quarantinedir ?>" /></td>
+    <td><?php print_string("configquarantinedir") ?></td>
+</tr>
+<tr valign=top>
+    <td align=right><p>clamfailureonupload</p></td>
+    <td><?php
+     unset($options);
+     $options['donothing'] = get_string('configclamdonothing');
+     $options['actlikevirus'] = get_string('configclamactlikevirus');
+  
+    choose_from_menu($options,"clamfailureonupload",$config->clamfailureonupload,"","","");
+    ?></td>  
+    <td><?php print_string("configclamfailureonupload"); ?></td>
+</tr>
 <tr valign="top">
     <td align="right"><p>fullnamedisplay:</td>
     <td>
diff --git a/admin/handlevirus.php b/admin/handlevirus.php
new file mode 100644 (file)
index 0000000..a2b1bf3
--- /dev/null
@@ -0,0 +1,99 @@
+<?
+/** This expects the output from a command like
+ * clamscan -r --infected --no-summary <files> 2>&1 | php thisfile.php 
+ * also it's important that the output of clamscan prints the FULL PATH to each infected file, so use absolute paths for area to scan
+ */
+
+
+$fd = fopen('php://stdin','r');
+if (!$fd) {
+    exit();
+}
+
+$FULLME='cron';
+require_once(dirname(dirname(__FILE__)).'/config.php');
+require_once($CFG->dirroot.'/lib/uploadlib.php'); // contains virus handling stuff.
+
+$site = get_site();
+
+while(!feof($fd)) {
+    $entry = fgets($fd);
+    if (strlen(trim($entry)) == 0) {
+        continue;
+    }
+    if (!$file = validate_line($entry)) {
+        continue;
+    }
+    $bits = explode('/',$file);
+    $a->filename = $bits[count($bits)-1];
+
+    if (!$log = get_record("log","module","upload","info",$file)) {
+        $a->action = clam_handle_infected_file($file,0,false);
+        clam_replace_infected_file($file);
+        notify_admins_unknown($file,$a);
+        continue;
+    }
+    $action = clam_handle_infected_file($file,$log->userid,true);
+    clam_replace_infected_file($file);
+    
+    $user = get_record("user","id",$log->userid);
+    $course = get_record("course","id",$log->course);
+    $subject = get_string('virusfoundsubject','moodle',$site->fullname);
+    $a->date = userdate($log->time);
+
+    $a->action = $action;
+    $a->course = $course->fullname;
+    $a->user = $user->firstname.' '.$user->lastname;
+
+    notify_user($user,$subject,$a);
+    notify_admins($user,$subject,$a);
+}
+fclose($fd);
+
+
+function notify_user($user,$subject,$a) {
+
+    if (!$user) {
+        return false;
+    }
+    $body = get_string('virusfoundlater','moodle',$a);
+    email_to_user($user,get_admin(),$subject,$body);
+}
+
+
+function notify_admins($user,$subject,$a) {
+
+    $admins = get_admins();
+
+    $body = get_string('virusfoundlateradmin','moodle',$a);
+    foreach ($admins as $admin) {
+        email_to_user($admin,$admin,$subject,$body);
+    }
+}
+
+function notify_admins_unknown($file,$a) {
+    
+    global $site;
+
+    $admins = get_admins();
+    $subject = get_string('virusfoundsubject','moodle',$site->fullname);
+    $body = get_string('virusfoundlateradminnolog','moodle',$a);
+    foreach ($admins as $admin) {
+        email_to_user($admin,$admin,$subject,$body);
+    }
+}
+
+function validate_line($line) {
+    if (strpos($line,"FOUND") === false) {
+        return false;
+    }
+    $index = strpos($line,":");
+    $file = substr($line,0,$index);
+    $file = preg_replace('/\/\//','/',$file);
+    if (!file_exists($file)) {
+        return false;
+    }
+    return $file;
+}
+
+?>
index c9fe9de12fc1d2f92c29e423fc5a1aa2f43bf981..b7d790644eefcd1cb958365fa02995784f5c5881 100644 (file)
@@ -85,6 +85,8 @@ $string['entrydeleted'] = 'Entry deleted';
 $string['entryexported'] = 'Entry succesfully exported';
 $string['entryishidden'] = '(this entry is currently hidden)';
 $string['entryleveldefaultsettings'] = 'Entry Level Default Settings';
+$string['entrysaved'] = 'This entry has been saved';
+$string['entryupdated'] = 'This entry has been updated';
 $string['entryusedynalink'] = 'This entry should be automatically linked';
 $string['explainaddentry'] = 'Add a new entry to the current glossary.<br />Concept and definition are mandatory fields.';
 $string['explainall'] = 'Shows ALL entries on one page';
index bd19dfb142179b2ad9e614eddfb9005e7b33967f..1480fbaa4667842cc59f3c0a4b7992865b4acb29 100644 (file)
@@ -143,6 +143,17 @@ $string['choosereportfilter'] = 'Choose a filter for the report';
 $string['choosetheme'] = 'Choose theme';
 $string['chooseuser'] = 'Choose a user';
 $string['city'] = 'City/town';
+$string['clambroken'] = 'Your administrator has enabled virus checking for file uploads but has misconfigured something.<br />Your file upload was NOT successful. Your administrator has been emailed to notify them so they can fix it.';
+$string['clamdeletedfile'] = 'The file has been deleted';
+$string['clamdeletedfilefailed'] ='The file could not be deleted';
+$string['clamemailsubject'] = '$a :: Clam AV notification';
+$string['clamfailed'] = 'Clam AV has failed to run.  The return error message was $a. Here is the output from Clam:';
+$string['clamlost'] = 'Moodle is configured to run clam on file upload, but the path supplied to Clam AV, $a,  is invalid.';
+$string['clamlostandactinglikevirus'] = 'In addition, moodle is configured so that if clam fails to run, files are treated like viruses.  This essentially means that no student can upload a file successfully until you fix this.';
+$string['clammovedfile'] = 'The file has been moved to your specified quarantine directory, the new location is $a';
+$string['clammovedfilebasic'] = 'The file has been moved to a quarantine directory.';
+$string['clamquarantinedirfailed'] = 'Could not move the file into your specified quarantine directory, $a. You need to fix this as files are being deleted if they\'re found to be infected.';
+$string['clamunknownerror'] = 'There was an unknown error with clam.';
 $string['cleaningtempdata'] = 'Cleaning temp data';
 $string['clicktochange'] = 'Click to change';
 $string['closewindow'] = 'Close this window';
@@ -152,6 +163,9 @@ $string['configallowunenroll'] = 'If this is set \'Yes\', then students are allo
 $string['configallusersaresitestudents'] = 'For activities on the front page of the site, should ALL users be considered as students?  If you answer \"Yes\", then any confirmed user account will be allowed to participate as a student in those activities.  If you answer \"No\", then only users who are already a participant in at least one course will be able to take part in those front page activities. Only admins and specially assigned teachers can act as teachers for these front page activities.';
 $string['configautologinguests'] = 'Should visitors be logged in as guests automatically when entering courses with guest access?';
 $string['configcachetext'] = 'For larger sites or sites that use text filters, this setting can really speed things up.  Copies of texts will be retained in their processed form for the time specified here.  Setting this too small may actually slow things down slightly,  but setting it too large may mean texts take too long to refresh (with new links, for example).';
+$string['configclamactlikevirus'] = 'Treat files like viruses';
+$string['configclamdonothing'] = 'Treat files as OK';
+$string['configclamfailureonupload'] = 'If you have configured clam to scan uploaded files, but it is configured incorrectly or fails to run for some unknown reason, how should it behave?  If you choose \'Treat files like viruses\', they\'ll be moved into the quarantine area, or deleted. If you choose \'Treat files as OK\', the files will be moved to the desination directory like normal. Either way, admins will be alerted that clam has failed.  If you choose \'Treat files like viruses\' and for some reason clam fails to run (usually because you have entered an invalid pathtoclam), ALL files that are uploaded will be moved to the given quarantine area, or deleted. Be careful with this setting.';
 $string['configcountry'] = 'If you set a country here, then this country will be selected by default on new user accounts.  To force users to choose a country, just leave this unset.';
 $string['configdebug'] = 'If you turn this on, then PHP\'s error_reporting will be increased so that more warnings are printed.  This is only useful for developers.';
 $string['configdeleteunconfirmed'] = 'If you are using email authentication, this is the period within which a response will be accepted from users.  After this period, old unconfirmed accounts are deleted.';
@@ -186,7 +200,10 @@ $string['confignoreplyaddress'] = 'Emails are sometimes sent out on behalf of a
 $string['confignotifyloginfailures'] = 'If login failures have been recorded, email notifications can be sent out.  Who should see these notifications?';
 $string['confignotifyloginthreshold'] = 'If notifications about failed logins are active, how many failed login attempts by one user or one IP address is it worth notifying about?';
 $string['configopentogoogle'] = 'If you enable this setting, then Google will be allowed to enter your site as a Guest.  In addition, people coming in to your site via a Google search will automatically be logged in as a Guest.  Note that this only provides transparent access to courses that already allow guest access.';
-$string['configproxyhost'] = 'If this <b>server</b> needs to use a proxy computer (eg a firewall) to access the Internet, then provide the proxy hostname and port here.  Otherwise leave it blank.';
+$string['configpathtoclam'] = 'Path to clam AV.  Probably something like /usr/bin/clamscan or /usr/bin/clamdscan. You need this in order for clam AV to run.';
+$string['configproxyhost'] = 'If this <B>server</B> needs to use a proxy computer (eg a firewall) to access the Internet, then provide the proxy hostname and port here.  Otherwise leave it blank.';
+$string['configquarantinedir'] = 'If you want clam AV to move infected files to a quarantine directory, enter it here. It must be writable by the webserver.  If you leave this blank, or if you enter a directory that doesn\'t exit or isn\'t writable, infected files will be deleted.  Do not include a trailing slash.';
+$string['configrunclamonupload'] = 'Run clam AV on file upload? You will need a correct path in pathtoclam for this to work.  (Clam AV is a free virus scanner that you can get from http://www.clamav.net/)';
 $string['configsecureforms'] = 'Moodle can use an additional level of security when accepting data from web forms. If this is enabled, then the browser\'s HTTP_REFERER variable is checked against the current form address.  In a very few cases this can cause problems if the user is using a firewall (eg Zonealarm) configured to strip HTTP_REFERER from their web traffic.  Symptoms are getting \'stuck\' on a form. If your users are having problems with the login page (for example) you might want to disable this setting, although it might leave your site more open to brute-force password attacks.  If in doubt, leave this set to \'Yes\'.';
 $string['configsessioncookie'] = 'This setting customises the name of the cookie used for Moodle sessions.  This is optional, and only useful to avoid cookies being confused when there is more than one copy of Moodle running within the same web site.';
 $string['configsessiontimeout'] = 'If people logged in to this site are idle for a long time (without loading pages) then they are automatically logged out (their session is ended).  This variable specifies how long this time should be.';
@@ -996,12 +1013,20 @@ $string['updatinga'] = 'Updating: $a';
 $string['updatingain'] = 'Updating $a->what in $a->in';
 $string['upload'] = 'Upload';
 $string['uploadafile'] = 'Upload a file';
+$string['uploadedfile'] = 'File uploaded successfully';
+$string['uploadfailednotrecovering'] = 'Your file upload has failed because there was a problem with one of the files, $a->name.<br/> Here is a log of the problems:<br />$a->problem<br />Not recovering.';
+$string['uploadfilelog'] = 'Upload log for file $a';
 $string['uploadedfileto'] = 'Uploaded $a->file to $a->directory';
+$string['uploadedfiletoobig'] = 'Sorry, but that file is too big (limit is $a bytes)';
 $string['uploadformlimit'] = 'Uploaded file exceeded the maximum size limit set by the form';
+$string['uploadlabel'] = 'Title:';
 $string['uploadnofilefound'] = 'No file was found - are you sure you selected one to upload?';
 $string['uploadnotallowed'] = 'Uploads are not allowed';
+$string['uploadoldfilesdeleted'] = 'The old file(s) in your upload area have been deleted';
 $string['uploadpartialfile'] = 'File was only partially uploaded';
 $string['uploadproblem'] = 'An unknown problem occurred while uploading the file \'$a\' (perhaps it was too large?)';
+$string['uploadrenamedchars'] = 'File was renamed from $a->oldname to $a->newname because of invalid characters.';
+$string['uploadrenamedcollision'] = 'File was renamed from $a->oldname to $a->newname because there was a filename conflict.';
 $string['uploadserverlimit'] = 'Uploaded file exceeded the maximum size limit set by the server';
 $string['uploadthisfile'] = 'Upload this file';
 $string['uploadusers'] = 'Upload users';
@@ -1023,6 +1048,13 @@ $string['userzones'] = 'User zones';
 $string['usingexistingcourse'] = 'Using existing course';
 $string['version'] = 'Version';
 $string['view'] = 'View';
+$string['virusfoundsubject'] = '$a: Virus found!';
+$string['virusfound'] = 'Attention administrator! Clam AV has found a virus in a file uploaded by $a->user for the course $a->course. Here is the output of clamscan:';
+$string['virusfounduser'] = 'The file you have uploaded, $a->filename, has been scanned by a virus checker and found to be infected! Your file upload was NOT successful.';
+$string['virusfoundlater'] = 'A file you uploaded on $a->date with the filename $a->filename for the course $a->course has since been found to contain a virus.  Here is a summary of what has happened to your file:'."\n\n".'$a->action'."\n\n".'If this was submitted work, you may want to resubmit it so that your tutor can see it.';
+$string['virusfoundlateradmin'] = 'Attention administrator! A file that was uploaded on $a->date with the filename $a->filename for the course $a->course by the user $a->user has since been found to contain a virus.  Here is a summary of what has happened to the file:'."\n\n".'$a->action'."\n\n".'The user has also been notified.';
+$string['virusfoundlateradminnolog'] = 'Attention administrator! A file that was uploaded with the filename $a->filename has since been found to contain a virus. Moodle was unable to resolve this file back to the user that originally uploaded it.'."\n\n".'Here is a summary of what has happened to the file:'."\n\n".'$a->action';
+$string['virusplaceholder'] = 'This file that has been uploaded was found to contain a virus and has been moved or delted and the user notified.';
 $string['webpage'] = 'Web page';
 $string['week'] = 'Week';
 $string['weekhide'] = 'Hide this week from $a';
diff --git a/lib/uploadlib.php b/lib/uploadlib.php
new file mode 100644 (file)
index 0000000..676f854
--- /dev/null
@@ -0,0 +1,589 @@
+<?php
+error_reporting(E_ALL ^ E_NOTICE);
+/**
+ * This class handles all aspects of fileuploading 
+ */
+class upload_manager {
+
+    var $files; // array to hold local copies of stuff in $_FILES
+    var $config; // holds all configuration stuff.
+    var $status; // keep track of if we're ok (errors for each file are kept in $files['whatever']['uploadlog']
+    var $course; // the course this file has been uploaded for (for logging and virus notifications)
+    var $inputname; // if we're only getting one file.
+
+    /**
+     * Constructor, sets up configuration stuff so we know how to act.
+     * Note: destination not taken as parameter as some modules want to use the insertid in the path and we need to check the other stuff first.
+     * @param $inputname - if this is given the upload manager will only process the file in $_FILES with this name.
+     * @param $deleteothers - whether to delete other files in the destination directory (optional,defaults to false)
+     * @param $handlecollisions - whether to use handle_filename_collision() or not. (optional, defaults to false)
+     * @param $course - the course the files are being uploaded for (for logging and virus notifications)
+     * @param $recoverifmultiple - if we come across a virus, or if a file doesn't validate or whatever, do we continue? optional, defaults to true.
+     * @param $modbytes - max bytes for this module - this and $course->maxbytes are used to get the maxbytes to use (lowest) from get_max_upload_file_size().
+     */
+    function upload_manager($inputname='',$deleteothers=false,$handlecollisions=false,$course=null,$recoverifmultiple=false,$modbytes=0) {
+        
+        global $CFG;
+        
+        $this->config->deleteothers = $deleteothers;
+        $this->config->handlecollisions = $handlecollisions;
+        $this->config->recoverifmultiple = $recoverifmultiple;
+        $this->config->maxbytes = get_max_upload_file_size($CFG->maxbytes,$course->maxbytes,$modbytes);
+        $this->files = array();
+        $this->status = false; 
+        $this->course = $course;
+        $this->inputname = $inputname;
+    }
+    
+    /** 
+     * Gets all entries out of $_FILES and stores them locally in $files
+     * Checks each one against get_max_upload_file_size and calls cleanfilename and scans them for viruses etc.
+     */
+    function preprocess_files() {
+        global $CFG;
+        foreach ($_FILES as $name => $file) {
+            $this->status = true; // only set it to true here so that we can check if this function has been called.
+            if (empty($this->inputname) || $name == $this->inputname) { // if we have input name, only process if it matches.
+                $file['originalname'] = $file['name']; // do this first for the log.
+                $this->files[$name] = $file; // put it in first so we can get uploadlog out in print_upload_log.
+                $this->status = $this->validate_file($this->files[$name],empty($this->inputname)); // default to only allowing empty on multiple uploads.
+                if (!$this->status && $this->files[$name]['error'] = 0 || $this->files[$name]['error'] == 4 && empty($this->inputname)) {
+                    // this shouldn't cause everything to stop.. modules should be responsible for knowing which if any are compulsory.
+                    continue; 
+                }
+                if ($this->status && $CFG->runclamonupload) {
+                    $this->status = clam_scan_file($this->files[$name],$this->course);
+                }
+                if (!$this->status) {
+                    if (!$this->config->recoverifmultiple && count($this->files) > 1) {
+                        $a->name = $this->files[$name]['originalname'];
+                        $a->problem = $this->files[$name]['uploadlog'];
+                        notify(get_string('uploadfailednotrecovering','moodle',$a));
+                        $this->status = false;
+                        return false;
+                    }
+                    else if (count($this->files) == 1) {
+                        notify($this->files[$name]['uploadlog']);
+                        $this->status = false;
+                        return false;
+                    }
+                }
+                else {
+                    $newname = clean_filename($this->files[$name]['name']);
+                    if ($newname != $this->files[$name]['name']) {
+                        $a->oldname = $this->files[$name]['name'];
+                        $a->newname = $newname;
+                        $this->files[$name]['uploadlog'] .= get_string('uploadrenamedchars','moodle',$a);
+                    }
+                    $this->files[$name]['name'] = $newname;
+                    $this->files[$name]['clear'] = true; // ok to save.
+                }
+            }
+        }
+        $this->status = true;
+        return true; // if we've got this far it means that we're recovering so we want status to be ok.
+    }
+
+    /**
+     * Validates a single file entry from _FILES
+     * @param $file - the entry from _FILES to validate
+     * @param $allowempty - this is to allow module owners to control which files are compulsory if this function is being called straight from the module.
+     * @return true if ok.
+     */
+    function validate_file(&$file,$allowempty=true) {
+        if (empty($file)) {
+            return $allowempty; // this shouldn't cause everything to stop.. modules should be responsible for knowing which if any are compulsory.
+        }
+        if (!is_uploaded_file($file['tmp_name']) || $file['size'] == 0) {
+            $file['uploadlog'] .= "\n".$this->get_file_upload_error($file);
+            if ($file['error'] == 0 || $file['error'] == 4) {
+                return $allowempty;
+            }
+            return false;
+        }
+        if ($file['size'] > $this->config->maxbytes) {
+            $file['uploadlog'] .= "\n".get_string("uploadedfiletoobig", "moodle", $this->config->maxbytes);
+            return false;
+        }
+        return true;
+    }
+
+    /** 
+     * Moves all the files to the destination directory.
+     * @param $destination - the destination directory.
+     * @return status;
+     */
+    function save_files($destination) {
+        global $CFG,$USER;
+        
+        if (!$this->status) { // preprocess_files hasn't been run
+            $this->preprocess_files();
+        }
+        if ($this->status) {
+            if (!(strpos($destination,$CFG->dataroot) === false)) {
+                // take it out for giving to make_upload_directory
+                $destination = substr($destination,strlen($CFG->dataroot)+1);
+            }
+
+            if ($destination{strlen($destination)-1} == "/") { // strip off a trailing / if we have one
+                $destination = substr($destination,0,-1);
+            }
+
+            if (!make_upload_directory($destination,true)) { //TODO maybe put this function here instead of moodlelib.php now.
+                $this->status = false;
+                return false;
+            }
+            
+            $destination = $CFG->dataroot.'/'.$destination; // now add it back in so we have a full path
+
+            $exceptions = array(); //need this later if we're deleting other files.
+
+            foreach (array_keys($this->files) as $i) {
+
+                if (!$this->files[$i]['clear']) {
+                    // not ok to save
+                    continue;
+                }
+
+                if ($this->config->handlecollisions) {
+                    $this->handle_filename_collision($destination,$this->files[$i]);
+                }
+                if (move_uploaded_file($this->files[$i]['tmp_name'], $destination.'/'.$this->files[$i]['name'])) {
+                    chmod($destination.'/'.$this->files[$i]['name'], $CFG->directorypermissions);
+                    $this->files[$i]['fullpath'] = $destination.'/'.$this->files[$i]['name'];
+                    $this->files[$i]['uploadlog'] .= "\n".get_string('uploadedfile');
+                    $this->files[$i]['saved'] = true;
+                    $exceptions[] = $this->files[$i]['name'];
+                    // now add it to the log (this is important so we know who to notify if a virus is found later on)
+                    clam_log_upload($this->files[$i]['fullpath'],$this->course);
+                    $savedsomething=true;
+                }
+            }
+            if ($savedsomething && $this->config->deleteothers) {
+                $this->delete_other_files($destination,$exceptions);
+            }
+        }
+        if (!$savedsomething) {
+            $this->status = false;
+            return false;
+        }
+        return $this->status;
+    }
+    
+    /**
+     * Wrapper function that calls preprocess_files and viruscheck_files and then save_files
+     * Modules that require the insert id in the filepath should not use this and call these functions seperately in the required order.
+     * @parameter $destination - where to save the uploaded files to.
+     */ 
+    function process_file_uploads($destination) {
+        if ($this->preprocess_files()) {
+            return $this->save_files($destination);
+        }
+        return false;
+    }
+
+    /** 
+     * Deletes all the files in a given directory except for the files in $exceptions (full paths)
+     * @param $destination - the directory to clean up.
+     * @param $exceptions - array of full paths of files to KEEP.
+     */
+    function delete_other_files($destination,$exceptions=null) {
+        if ($filestodel = get_directory_list($destination)) {
+            foreach ($filestodel as $file) {
+                if (!is_array($exceptions) || !in_array($file,$exceptions)) {
+                    unlink("$destination/$file");
+                    $deletedsomething = true;
+                }
+            }
+        }
+        if ($deletedsomething) {
+            notify(get_string('uploadoldfilesdeleted'));
+        }
+    }
+    
+    /**
+     * Handles filename collisions - if the desired filename exists it will rename it according to the pattern in $format
+     * @param $destination - destination directory (to check existing files against)
+     * @param $file - the current file from $files we're processing.
+     * @param $format - the printf style format to rename the file to (defaults to filename_number.extn)
+     * @return new filename.
+     */
+    function handle_filename_collision($destination,&$file,$format='%s_%d.%s') {
+        $bits = explode('.',$file['name']);
+        // check for collisions and append a nice numberydoo.
+        if (file_exists($destination.'/'.$file['name'])) {
+            $a->oldname = $file['name'];
+            for ($i = 1; true; $i++) {
+                $try = sprintf($format,$bits[0],$i,$bits[1]);
+                if ($this->check_before_renaming($destination,$try,$file)) {
+                    $file['name'] = $try;
+                    break;
+                }
+            }
+            $a->newname = $file['name'];
+            $file['uploadlog'] .= "\n".get_string('uploadrenamedcollision','moodle',$a);
+        }
+    }
+    
+    /**
+     * This function checks a potential filename against what's on the filesystem already and what's been saved already.
+     */
+    function check_before_renaming($destination,$nametocheck,$file) {
+        if (!file_exists($destination.'/'.$nametocheck)) {
+            return true;
+        }
+        if ($this->config->deleteothers) {
+            foreach ($this->files as $tocheck) {
+                // if we're deleting files anyway, it's not THIS file and we care about it and it has the same name and has already been saved..
+                if ($file['tmp_name'] != $tocheck['tmp_name'] && $tocheck['clear'] && $nametocheck == $tocheck['name'] && $tocheck['saved']) {
+                    $collision = true;
+                }
+            }
+            if (!$collision) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    
+    function get_file_upload_error(&$file) {
+        
+        switch ($file['error']) {
+        case 0: // UPLOAD_ERR_OK
+            if ($file['size'] > 0) {
+                $errmessage = get_string('uploadproblem', $file['name']);
+            } else {
+                $errmessage = get_string('uploadnofilefound'); /// probably a dud file name
+            }
+            break;
+            
+        case 1: // UPLOAD_ERR_INI_SIZE
+            $errmessage = get_string('uploadserverlimit');
+            break;
+            
+        case 2: // UPLOAD_ERR_FORM_SIZE
+            $errmessage = get_string('uploadformlimit');
+            break;
+            
+        case 3: // UPLOAD_ERR_PARTIAL
+            $errmessage = get_string('uploadpartialfile');
+            break;
+            
+        case 4: // UPLOAD_ERR_NO_FILE
+            $errmessage = get_string('uploadnofilefound');
+            break;
+            
+        default:
+            $errmessage = get_string('uploadproblem', $file['name']);
+        }
+        return $errmessage;
+    }
+    
+    /**
+     * prints a log of everything that happened (of interest) to each file in _FILES
+     * @param $return - optional, defaults to false (log is echoed)
+     */
+    function print_upload_log($return=false) {
+        foreach (array_keys($this->files) as $i => $key) {
+            $str .= '<b>'.get_string('uploadfilelog','moodle',$i+1).' '
+                .((!empty($this->files[$key]['originalname'])) ? '('.$this->files[$key]['originalname'].')' : '')
+                .'</b> :'.nl2br($this->files[$key]['uploadlog']).'<br />';
+        }
+        if ($return) {
+            return $str;
+        }
+        echo $str;
+    }
+
+    /**
+     * If we're only handling one file (if inputname was given in the constructor) this will return the (possibly changed) filename of the file.
+     */
+    function get_new_filename() {
+        if (!empty($this->inputname) && count($this->files) == 1) {
+            return $this->files[$this->inputname]['name'];
+        }
+        return false;
+    }
+
+    /** 
+     * If we're only handling one file (if inputname was given in the constructor) this will return the ORIGINAL filename of the file.
+     */
+    function get_original_filename() {
+        if (!empty($this->inputname) && count($this->files) == 1) {
+            return $this->files[$this->inputname]['originalname'];
+        }
+        return false;
+    }
+}
+
+/**************************************************************************************
+THESE FUNCTIONS ARE OUTSIDE THE CLASS BECAUSE THEY NEED TO BE CALLED FROM OTHER PLACES.
+FOR EXAMPLE CLAM_HANDLE_INFECTED_FILE AND CLAM_REPLACE_INFECTED_FILE USED FROM CRON
+UPLOAD_PRINT_FORM_FRAGMENT DOESN'T REALLY BELONG IN THE CLASS BUT CERTAINLY IN THIS FILE
+***************************************************************************************/
+
+
+/**
+ * This function prints out a number of upload form elements
+ * @param $numfiles - the number of elements required (optional, defaults to 1)
+ * @param $names - array of element names to use (optional, defaults to FILE_n)
+ * @param $descriptions - array of strings to be printed out before each file bit.
+ * @param $uselabels - whether to output text fields for file descriptions or not (optional, defaults to false)
+ * @param $labelnames - array of element names to use for labels (optional, defaults to LABEL_n)
+ * @param $coursebytes 
+ * @param $modbytes - these last two are used to calculate upload max size ( using get_max_upload_file_size)
+ * @param $return - whether to return the string (defaults to false - string is echoed)
+ */ 
+function upload_print_form_fragment($numfiles=1,$names=null,$descriptions=null,$uselabels=false,$labelnames=null,$coursebytes=0,$modbytes=0,$return=false) {
+    global $CFG;
+    $maxbytes = get_max_upload_file_size($CFG->maxbytes,$coursebytes,$modbytes);
+    $str = '<input type="hidden" name="MAX_FILE_SIZE" value="'.$maxbytes.'" />'."\n";
+    for ($i = 0; $i < $numfiles; $i++) {
+        if (is_array($descriptions) && !empty($descriptions[$i])) {
+            $str .= '<b>'.$descriptions[$i].'</b><br />';
+        }
+        $str .= '<input type="file" size="50" name="'.((is_array($names) && !empty($names[$i])) ? $names[$i] : 'FILE_'.$i).'" /><br />'."\n";
+        if ($uselabels) {
+            $str .= get_string('uploadlabel').' <input type="text" size="50" name="'
+                .((is_array($labelnames) && !empty($labelnames[$i])) ? $labelnames[$i] : 'LABEL_'.$i)
+                .'" /><br /><br />'."\n";
+        }
+    }
+    if ($return) {
+        return $str;
+    }
+    else {
+        echo $str;
+    }
+}
+
+
+/**
+ * Deals with an infected file - either moves it to a quarantinedir 
+ * (specified in CFG->quarantinedir) or deletes it.
+ * If moving it fails, it deletes it.
+ * @param file full path to the file
+ * @param userid - if not used, defaults to $USER->id (there in case called from cron)
+ * @param basiconly - admin level reporting or user level reporting.
+ * @return a string of what it did.
+ */
+function clam_handle_infected_file($file,$userid=0,$basiconly=false) {
+    
+    global $CFG,$USER;
+    if ($USER && !$userid) {
+        $userid = $USER->id;
+    }
+    $delete = true;
+    if (file_exists($CFG->quarantinedir) && is_dir($CFG->quarantinedir) && is_writable($CFG->quarantinedir)) {
+        $now = date('YmdHis');
+        if (rename($file,$CFG->quarantinedir.'/'.$now.'-user-'.$userid.'-infected')) { 
+            $delete = false;
+            if ($basiconly) {
+                $notice .= "\n".get_string('clammovedfilebasic');
+            }
+            else {
+                $notice .= "\n".get_string('clammovedfile','moodle',$CFG->quarantinedir.'/'.$now.'-user-'.$userid.'-infected');
+            }
+        }
+        else {
+            if ($basiconly) {
+                $notice .= "\n".get_string('clamdeletedfile');
+            }
+            else {
+                $notice .= "\n".get_string('clamquarantinedirfailed','moodle',$CFG->quarantinedir);
+            }
+        }
+    }
+    else {
+        if ($basiconly) {
+            $notice .= "\n".get_string('clamdeletedfile');
+        }
+        else {
+            $notice .= "\n".get_string('clamquarantinedirfailed','moodle',$CFG->quarantinedir);
+        }
+    }
+    if ($delete) {
+        if (unlink($file)) {
+            $notice .= "\n".get_string('clamdeletedfile');
+        }
+        else {
+            if ($basiconly) {
+                // still tell the user the file has been deleted. this is only for admins.
+                $notice .= "\n".get_string('clamdeletedfile');
+            }
+            else {
+                $notice .= "\n".get_string('clamdeletedfilefailed');
+            }
+        }
+    }
+    return $notice;
+}
+
+/**
+ * Replaces the given file with a string to notify that the original file had a virus.
+ * This is to avoid missing files but could result in the wrong content-type.
+ * @param file - full path to the file.
+ */
+function clam_replace_infected_file($file) {
+    $newcontents = get_string('virusplaceholder');
+    if (!$f = fopen($file,'w')) {
+        return false;
+    }
+    if (!fwrite($f,$newcontents)) {
+        return false;
+    }
+    return true;
+}
+
+
+/**
+ * If $CFG->runclamonupload is set, we scan a given file. (called from preprocess_files)
+ * This function will add on a uploadlog index in $file.
+ * @param $file - the file to scan from $files. or an absolute path to a file.
+ * @return 1 if good, 0 if something goes wrong (opposite from actual error code from clam)
+ */ 
+function clam_scan_file(&$file,$course) {
+    global $CFG,$USER;
+
+    if (is_array($file) && is_uploaded_file($file['tmp_name'])) { // it's from $_FILES
+        $appendlog = true; 
+        $fullpath = $file['tmp_name'];
+    }
+    else if (file_exists($file)) { // it's a path to somewhere on the filesystem!
+        $fullpath = $file;
+    }
+    else {
+        return false; // erm, what is this supposed to be then, huh?
+    }
+
+    if (!$CFG->pathtoclam || !file_exists($CFG->pathtoclam) || !is_executable($CFG->pathtoclam)) {
+        $newreturn = 1;
+        $notice = get_string('clamlost','moodle',$CFG->pathtoclam);
+        if ($CFG->clamfailureonupload == 'actlikevirus') {
+            $notice .= "\n".get_string('clamlostandactinglikevirus');
+            $notice .= "\n".clam_handle_infected_file($fullpath);
+            $newreturn = false; 
+        }
+        clam_mail_admins($notice);
+        return $newreturn; // return 1 if we're allowing clam failures
+    }
+    
+    $cmd = $CFG->pathtoclam.' '.$fullpath." 2>&1";
+    
+    // before we do anything we need to change perms so that clamscan can read the file (clamdscan won't work otherwise)
+    chmod($fullpath,0644);
+    
+    exec($cmd,$output,$return);
+    
+    
+    switch ($return) {
+    case 0: // glee! we're ok.
+        return 1; // translate clam return code into reasonable return code consistent with everything else.
+    case 1:  // bad wicked evil, we have a virus.
+        if (!empty($course)) {
+            $info->course = $course->fullname;
+        }
+        else {
+            $info->course = 'No course';
+        }
+        $info->user = $USER->firstname.' '.$USER->lastname;
+        $notice = get_string('virusfound','moodle',$info);
+        $notice .= "\n\n".implode("\n",$output);
+        $notice .= "\n\n".clam_handle_infected_file($fullpath); 
+        clam_mail_admins($notice);
+        if ($appendlog) {
+            $info->filename = $file['originalname'];
+            $file['uploadlog'] .= "\n".get_string('virusfounduser','moodle',$info);
+            $file['virus'] = 1;
+        }
+        return false; // in this case, 0 means bad.
+    default: 
+        // error - clam failed to run or something went wrong
+        $notice .= get_string('clamfailed','moodle',get_clam_error_code($return));
+        $notice .= "\n\n".implode("\n",$output);
+        $newreturn = true;
+        if ($CFG->clamfailureonupload == 'actlikevirus') {
+            $notice .= "\n".clam_handle_infected_file($fullpath);
+            $newreturn = false;
+        }
+        clam_mail_admins($notice);
+        if ($appendlog) {
+            $file['uploadlog'] .= "\n".get_string('clambroken');
+            $file['clam'] = 1;
+        }
+        return $newreturn; // return 1 if we're allowing failures.
+    }
+}
+
+/**
+ * emails admins about a clam outcome
+ * @param notice - the body of the email.
+ */
+function clam_mail_admins($notice) {
+    
+    $site = get_site();
+        
+    $subject = get_string('clamemailsubject','moodle',$site->fullname);
+    $admins = get_admins();
+    foreach ($admins as $admin) {
+        email_to_user($admin,get_admin(),$subject,$notice);
+    }
+}
+
+
+function get_clam_error_code($returncode) {
+    $returncodes = array();
+    $returncodes[0] = 'No virus found.';
+    $returncodes[1] = 'Virus(es) found.';
+    $returncodes[2] = ' An error occured'; // specific to clamdscan
+    // all after here are specific to clamscan
+    $returncodes[40] = 'Unknown option passed.';
+    $returncodes[50] = 'Database initialization error.';
+    $returncodes[52] = 'Not supported file type.';
+    $returncodes[53] = 'Can\'t open directory.';
+    $returncodes[54] = 'Can\'t open file. (ofm)';
+    $returncodes[55] = 'Error reading file. (ofm)';
+    $returncodes[56] = 'Can\'t stat input file / directory.';
+    $returncodes[57] = 'Can\'t get absolute path name of current working directory.';
+    $returncodes[58] = 'I/O error, please check your filesystem.';
+    $returncodes[59] = 'Can\'t get information about current user from /etc/passwd.';
+    $returncodes[60] = 'Can\'t get information about user \'clamav\' (default name) from /etc/passwd.';
+    $returncodes[61] = 'Can\'t fork.'; 
+    $returncodes[63] = 'Can\'t create temporary files/directories (check permissions).';
+    $returncodes[64] = 'Can\'t write to temporary directory (please specify another one).';
+    $returncodes[70] = 'Can\'t allocate and clear memory (calloc).';
+    $returncodes[71] = 'Can\'t allocate memory (malloc).';
+    if ($returncodes[$returncode])
+       return $returncodes[$returncode];
+    return get_string('clamunknownerror');
+
+}
+
+/**
+ * adds a file upload to the log table so that clam can resolve the filename to the user later if necessary
+ */
+function clam_log_upload($newfilepath,$course=null) {
+    global $CFG,$USER;
+    // get rid of any double // that might have appeared
+    $newfilepath = preg_replace('/\/\//','/',$newfilepath);
+    if (strpos($newfilepath,$CFG->dataroot) === false) {
+        $newfilepath = $CFG->dataroot.'/'.$newfilepath;
+    }
+    $CFG->debug=10;
+    $courseid = 0;
+    if ($course) {
+        $courseid = $course->id;
+    }
+    add_to_log($courseid,"upload","upload","",$newfilepath);
+}
+
+/**
+ * some of the modules allow moving attachments (glossary), in which case we need to hunt down an original log and change the path.
+ */
+function clam_change_log($oldpath,$newpath) {
+    global $CFG;
+    $sql = "UPDATE {$CFG->prefix}log SET info = '$newpath' WHERE module = 'upload' AND info = '$oldpath'";
+    execute_sql($sql);
+}
+?>
\ No newline at end of file
index 1cee5d6905a8ebd80298e7d6a714194e46b24d4d..992919ca0d6acae65d120efb9d63cf7b1219a1ed 100644 (file)
@@ -661,6 +661,7 @@ function assignment_print_user_files($assignment, $user) {
     }
 }
 
+// this function should be defunct now that we're using uploadlib.php
 function assignment_delete_user_files($assignment, $user, $exception) {
 // Deletes all the user files in the assignment area for a user
 // EXCEPT for any file named $exception
@@ -680,11 +681,13 @@ function assignment_delete_user_files($assignment, $user, $exception) {
 function assignment_print_upload_form($assignment) {
 // Arguments are objects
 
+    global $CFG;
+
     echo "<div align=CENTER>";
     echo "<form enctype=\"multipart/form-data\" method=\"POST\" action=\"upload.php?id=$assignment->id\">";
-    echo " <input type=hidden name=MAX_FILE_SIZE value=\"$assignment->maxbytes\" />";
     echo " <input type=hidden name=id value=\"$assignment->id\" />";
-    echo " <input name=\"newfile\" type=\"file\" size=\"50\" />";
+    require_once($CFG->dirroot.'/lib/uploadlib.php');
+    upload_print_form_fragment(1,array('newfile'),false,null,0,$assignment->maxbytes,false);
     echo " <input type=submit name=save value=\"".get_string("uploadthisfile")."\" />";
     echo "</form>";
     echo "</div>";
index 240f666ddb05134d06e73d85cb7a3eea6f0d4e70..98783ca4f04665e2ef08c0c14f935a887256692b 100644 (file)
@@ -2,15 +2,9 @@
 
     require_once("../../config.php");
     require_once("lib.php");
-    
 
     require_variable($id);          // Assignment ID
 
-    if (!empty($_FILES['newfile'])) {
-        $newfile = $_FILES['newfile'];
-    }
-
-
     if (! $assignment = get_record("assignment", "id", $id)) {
         error("Not a valid assignment ID");
     }
@@ -25,8 +19,6 @@
 
     require_login($course->id);
 
-    add_to_log($course->id, "assignment", "upload", "view.php?a=$assignment->id", "$assignment->id", $cm->id);
-
     $strassignments = get_string("modulenameplural", "assignment");
     $strassignment  = get_string("modulename", "assignment");
     $strupload      = get_string("upload");
         }
     }
 
-    if (! $dir = assignment_file_area($assignment, $USER)) {
-        error("Sorry, an error in the system prevents you from uploading files: contact your teacher or system administrator");
-    }
-
-    if (empty($newfile)) {
-        notify(get_string("uploadfiletoobig", "assignment",  get_max_upload_file_size($CFG->maxbytes, $course->maxbytes, $assignment->maxbytes)) );
-
-    } else if (is_uploaded_file($newfile['tmp_name']) and $newfile['size'] > 0) {
-        $newfile_name = clean_filename($newfile['name']);
-        if ($newfile_name) {
-            if (move_uploaded_file($newfile['tmp_name'], "$dir/$newfile_name")) {
-                chmod("$dir/$newfile_name", $CFG->directorypermissions);
-                assignment_delete_user_files($assignment, $USER, $newfile_name);
-                if ($submission) {
-                    $submission->timemodified = time();
-                    $submission->numfiles     = 1;
-                    $submission->comment = addslashes($submission->comment);
-                    if (update_record("assignment_submissions", $submission)) {
-                        print_heading(get_string("uploadsuccess", "assignment", $newfile_name) );
-                    } else {
-                        notify(get_string("uploadfailnoupdate", "assignment"));
-                    }
-                } else {
-                    $newsubmission->assignment   = $assignment->id;
-                    $newsubmission->userid       = $USER->id;
-                    $newsubmission->timecreated  = time();
-                    $newsubmission->timemodified = time();
-                    $newsubmission->numfiles     = 1;
-                    if (insert_record("assignment_submissions", $newsubmission)) {
-                        print_heading(get_string("uploadsuccess", "assignment", $newfile_name) );
-                    } else {
-                        notify(get_string("uploadnotregistered", "assignment", $newfile_name) );
-                    }
-                }
+    $dir = assignment_file_area_name($assignment,$USER);
+    require_once($CFG->dirroot.'/lib/uploadlib.php');
+    $um = new upload_manager('newfile',true,false,$course,false,$assignment->maxbytes);
+    $newfile_name = $um->get_new_filename();
+    if ($um->process_file_uploads($dir)) {
+        if ($submission) {
+            $submission->timemodified = time();
+            $submission->numfiles     = 1;
+            $submission->comment = addslashes($submission->comment);
+            if (update_record("assignment_submissions", $submission)) {
+                print_heading(get_string('uploadedfile'));
             } else {
-                notify(get_string("uploaderror", "assignment") );
+                notify(get_string("uploadfailnoupdate", "assignment"));
             }
         } else {
-            notify(get_string("uploadbadname", "assignment") );
-        }
-    } else {
-
-        print_file_upload_error();
-
+            $newsubmission->assignment   = $assignment->id;
+            $newsubmission->userid       = $USER->id;
+            $newsubmission->timecreated  = time();
+            $newsubmission->timemodified = time();
+            $newsubmission->numfiles     = 1;
+            if (insert_record("assignment_submissions", $newsubmission)) {
+                add_to_log($course->id, "assignment", "upload", "view.php?a=$assignment->id", "$assignment->id", $cm->id);
+                print_heading(get_string('uploadedfile'));
+            } else {
+                notify(get_string("uploadnotregistered", "assignment", $newfile_name) );
+            }
+        } 
     }
-    
+    // upload class will take care of printing out errors.
+
     print_continue("view.php?a=$assignment->id");
 
     print_footer($course);
 
-
 ?>
index 05a2ff1bd6b72f2bc7a007a160c1f2d51a0b5e5c..9fbde293220c394b04f97a467476e317811d112a 100644 (file)
@@ -2856,6 +2856,8 @@ function exercise_print_time_to_deadline($time) {
 ///////////////////////////////////////////////////////////////////////////////////////////////
 function exercise_print_upload_form($exercise) {
 
+    global $CFG;
+
     if (! $course = get_record("course", "id", $exercise->course)) {
         error("Course is misconfigured");
         }
@@ -2865,10 +2867,9 @@ function exercise_print_upload_form($exercise) {
 
     echo "<div align=\"center\">";
     echo "<form enctype=\"multipart/form-data\" method=\"POST\" action=\"upload.php\">";
-    echo " <input type=\"hidden\" name=\"maxbytes\" value=\"$exercise->maxbytes\" />";
     echo " <input type=\"hidden\" name=\"id\" value=\"$cm->id\" />";
-    echo "<b>".get_string("title", "exercise")."</b>: <input name=\"title\" type=\"text\" size=\"60\" maxsize=\"100\" /><br /><br />\n";
-    echo " <input name=\"newfile\" type=\"file\" size=\"50\" />";
+    require_once($CFG->dirroot.'/lib/uploadlib.php');
+    upload_print_form_fragment(1,array('newfile'),null,true,array('title'),$course->maxbytes,$exercise->maxbytes,false);
     echo " <input type=\"submit\" name=\"save\" value=\"".get_string("uploadthisfile")."\" />";
     echo " (".get_string("maximumupload").": ".display_size($exercise->maxbytes).")\n"; 
     echo "</form>";
index b881c4aea80ec3216b760089d6b1682fe37ba0a4..ef2efa9b27b214d37595043737b3aa14b805b394 100644 (file)
@@ -7,8 +7,6 @@
     require_variable($id);          // course module ID
     $timenow = time();
 
-    $newfile = $HTTP_POST_FILES["newfile"];
-
     // get some esential stuff...
     if (! $cm = get_record("course_modules", "id", $id)) {
         error("Course Module ID was incorrect");
         notify(get_string("notitlegiven", "exercise") );
     }
     else {  
-        if (is_uploaded_file($newfile['tmp_name']) and $newfile['size'] > 0) {
-            if ($newfile['size'] > $exercise->maxbytes) {
-                notify(get_string("uploadfiletoobig", "assignment", $exercise->maxbytes));
-            } 
+        require_once($CFG->dirroot.'/lib/uploadlib.php');
+        $um = new upload_manager('newfile',false,false,$course,false,$exercise->maxbytes);
+        if ($um->preprocess_files()) {
+            $newsubmission->exerciseid   = $exercise->id;
+            if (isteacher($course->id)) {
+                // it's an exercise submission, flag it as such
+                $newsubmission->userid         = 0;
+                $newsubmission->isexercise = 1;  // it's a description of an exercise
+            }
             else {
-                $newfile_name = clean_filename($newfile['name']);
-                if ($newfile_name) {
-                    $newsubmission->exerciseid   = $exercise->id;
-                    if (isteacher($course->id)) {
-                        // it's an exercise submission, flag it as such
-                        $newsubmission->userid         = 0;
-                        $newsubmission->isexercise = 1;  // it's a description of an exercise
-                    }
-                    else {
-                        $newsubmission->userid = $USER->id;
-                    }
-                    $newsubmission->title  = $title;
-                    $newsubmission->timecreated  = $timenow;
-                    if ($timenow > $exercise->deadline) {
-                        $newsubmission->late = 1;
-                    }
-                    if (!$newsubmission->id = insert_record("exercise_submissions", $newsubmission)) {
-                        error("exercise upload: Failure to create new submission record!");
-                    }
-                    if (! $dir = exercise_file_area($exercise, $newsubmission)) {
-                        error("Sorry, an error in the system prevents you from uploading files: contact your teacher or system administrator");
-                    }
-                    if (move_uploaded_file($newfile['tmp_name'], "$dir/$newfile_name")) {
-                        add_to_log($course->id, "exercise", "submit", "view.php?id=$cm->id", "$exercise->id");
-                        print_heading(get_string("uploadsuccess", "assignment", $newfile_name) );
-                    }
-                    else {
-                        notify(get_string("uploaderror", "assignment") );
-                    }
-                    // clear resubmit flags
-                    if (!set_field("exercise_submissions", "resubmit", 0, "exerciseid", $exercise->id, "userid", $USER->id)) {
-                        error("Exercise Upload: unable to reset resubmit flag");
-                    }
-                } 
-                else {
-                    notify(get_string("uploadbadname", "assignment") );
-                }
+                $newsubmission->userid = $USER->id;
             }
-        }
-        elseif (!is_uploaded_file($newfile['tmp_name']) and !$newfile['size'] > 0 and $newfile['name']) {
-            notify(get_string("uploadfiletoobig", "assignment", $exercise->maxbytes));
-        } else {
-            notify(get_string("uploadnofilefound", "assignment"));
-        }
+            $newsubmission->title  = $title;
+            $newsubmission->timecreated  = $timenow;
+            if ($timenow > $exercise->deadline) {
+                $newsubmission->late = 1;
+            }
+            if (!$newsubmission->id = insert_record("exercise_submissions", $newsubmission)) {
+                error("exercise upload: Failure to create new submission record!");
+            }
+            $dir = exercise_file_area_name($exercise, $newsubmission);
+            if ($um->save_files($dir)) {
+                add_to_log($course->id, "exercise", "submit", "view.php?id=$cm->id", "$exercise->id");
+                print_heading(get_string("uploadsuccess", "assignment", $um->get_new_filename()) );
+            }
+            // upload manager will print errors.
+            // clear resubmit flags
+            if (!set_field("exercise_submissions", "resubmit", 0, "exerciseid", $exercise->id, "userid", $USER->id)) {
+                error("Exercise Upload: unable to reset resubmit flag");
+            }
+        } 
+        // upload manager will print errors.
     }
     print_continue("view.php?id=$cm->id");
 
index d4884f5790714b45976a6e6ddc73eae32df7868c..4da192053aa50a2515745774f96a05da6cc65c5f 100644 (file)
@@ -1907,6 +1907,8 @@ function forum_move_attachments($discussion, $forumid) {
 
     global $CFG;
 
+    require_once($CFG->dirroot.'/lib/uploadlib.php');
+
     $return = true;
 
     if ($posts = get_records_select("forum_posts", "discussion = '$discussion->id' AND attachment <> ''")) {
@@ -1918,9 +1920,13 @@ function forum_move_attachments($discussion, $forumid) {
                 $newpost = $oldpost;
                 $newpost->forum = $forumid;
                 $newpostdir = forum_file_area($newpost);
+                $files = get_directory_list($oldpostdir); // get it before we rename it.
                 if (! @rename($oldpostdir, $newpostdir)) {
                     $return = false;
                 }
+                foreach ($files as $file) {
+                    clam_change_log($oldpostdir.'/'.$file,$newpostdir.'/'.$file);
+                }
             }
         }
     }
@@ -1979,17 +1985,13 @@ function forum_print_attachments($post, $return=NULL) {
     return $imagereturn;
 }
 
-function forum_add_attachment($post, $newfile) {
+function forum_add_attachment($post, $inputname) {
 // $post is a full post record, including course and forum
 // $newfile is a full upload array from $_FILES
 // If successful, this function returns the name of the file
 
     global $CFG;
 
-    if (empty($newfile['name'])) {
-        return "";
-    }
-
     if (!$forum = get_record("forum", "id", $post->forum)) {
         return "";
     }
@@ -1998,35 +2000,13 @@ function forum_add_attachment($post, $newfile) {
         return "";
     }
 
-    $maxbytes = get_max_upload_file_size($CFG->maxbytes, $course->maxbytes, $forum->maxbytes);
-
-    $newfile_name = clean_filename($newfile['name']);
-
-    if (valid_uploaded_file($newfile)) {
-        if ($maxbytes and $newfile['size'] > $maxbytes) {
-            return "";
-        }
-        if (! $newfile_name) {
-            notify("This file had a wierd filename and couldn't be uploaded");
-
-        } else if (! $dir = forum_file_area($post)) {
-            notify("Attachment could not be stored");
-            $newfile_name = "";
-
-        } else {
-            if (move_uploaded_file($newfile['tmp_name'], "$dir/$newfile_name")) {
-                chmod("$dir/$newfile_name", $CFG->directorypermissions);
-                forum_delete_old_attachments($post, $newfile_name);
-            } else {
-                notify("An error happened while saving the file on the server");
-                $newfile_name = "";
-            }
-        }
-    } else {
-        $newfile_name = "";
+    require_once($CFG->dirroot.'/lib/uploadlib.php');
+    $um = new upload_manager($inputname,true,false,$course,false,$forum->maxbytes);
+    $dir = forum_file_area_name($post);
+    if ($um->process_file_uploads($dir)) {
+        return $um->get_new_filename();
     }
-
-    return $newfile_name;
+    // upload manager will print any errors.
 }
 
 function forum_add_new_post($post) {
@@ -2034,14 +2014,13 @@ function forum_add_new_post($post) {
     $post->created = $post->modified = time();
     $post->mailed = "0";
 
-    $newfile = $post->attachment;
     $post->attachment = "";
 
     if (! $post->id = insert_record("forum_posts", $post)) {
         return false;
     }
 
-    if ($post->attachment = forum_add_attachment($post, $newfile)) {
+    if ($post->attachment = forum_add_attachment($post, 'attachment')) {
         set_field("forum_posts", "attachment", $post->attachment, "id", $post->id);
     }
 
@@ -2060,7 +2039,7 @@ function forum_update_post($post) {
         set_field("forum_discussions", "name", $post->subject, "id", $post->discussion);
     }
 
-    if ($newfilename = forum_add_attachment($post, $post->attachment)) {
+    if ($newfilename = forum_add_attachment($post, 'attachment')) {
         $post->attachment = $newfilename;
     } else {
         unset($post->attachment);
@@ -2101,7 +2080,7 @@ function forum_add_discussion($discussion) {
         return 0;
     }
 
-    if ($post->attachment = forum_add_attachment($post, $discussion->attachment)) {
+    if ($post->attachment = forum_add_attachment($post, 'attachment')) {
         set_field("forum_posts", "attachment", $post->attachment, "id", $post->id); //ignore errors
     }
 
index 6a3bdd8d4bdee4d0fbca0e385d4c8af0e83e8001..52b6778d27e09023e77d7d4c256adabc2b4e2387 100644 (file)
@@ -89,9 +89,9 @@
     <td align="right"><p><b><?php print_string("attachment", "forum") ?>:<br />(<?php print_string("optional") ?>)&nbsp;</b></p></td>
     <td>
     <?php $maxbytes = get_max_upload_file_size($CFG->maxbytes, $course->maxbytes, $forum->maxbytes); ?>
-    <input type="hidden" name="MAX_FILE_SIZE" value="<?php echo $maxbytes ?>" />
-    <input type="file" name="attachment" size="40" /> 
     <?php 
+       require_once($CFG->dirroot.'/lib/uploadlib.php');
+       upload_print_form_fragment(1,array('attachment'),null,false,null,$course->maxbytes,$forum->maxbytes,false);
        helpbutton("attachment", get_string("attachment", "forum"), "forum"); 
        print_string("maxsize", "", display_size($maxbytes)); 
     ?>
index b45930940bbd33d6ff099555dfffdfa6cc0fb5c6..030f1429e3f842c53e54b6d0bd7c884560e05b00 100644 (file)
@@ -158,9 +158,9 @@ if (isset($errors)) {
 <tr valign="top">
     <td align="right"><p><b><?php print_string("attachment", "glossary") ?>:<br />(<?php print_string("optional") ?>)&nbsp;</b></p></td>
     <td>
-    <input type="hidden" name="MAX_FILE_SIZE" value="<?php echo get_max_upload_file_size($CFG->maxbytes, $course->maxbytes) ?>" />
-    <input type="file" name="attachment" size="40" />
     <?php
+       require_once($CFG->dirroot.'/lib/uploadlib.php');
+       upload_print_form_fragment(1,array('attachment'),null,false,null,$course->maxbytes,0,false);
        helpbutton("attachment", get_string("attachment", "glossary"), "glossary");
        print_string("maxsize", "", display_size(get_max_upload_file_size($CFG->maxbytes, $course->maxbytes)));
     ?>
@@ -170,8 +170,8 @@ if (isset($errors)) {
 <td colspan="2">
     <p align="center">
     <?php if (isset($newentry->id)) {
-        echo "<input type=\"hidden\" name="e" value=\"$newentry->id\" />";
-      }
+        echo "<input type=\"hidden\" name=\"e\" value=\"$newentry->id\" />";
+    }
   ?>
 
   <input type="hidden" name="husedynalink" value="1" />
index ece35a86af341761b3208989d74074930f6cdcb5..91219b67a83784ffbf56858aad3ca611f8c53f69 100644 (file)
@@ -89,7 +89,13 @@ if ( $confirm ) {
         print_footer($course);
         die;
     }
-
+    print_header_simple(strip_tags("$glossary->name"), "",
+                        "<A HREF=\"index.php?id=$course->id\">$strglossaries</A> ->
+              <A HREF=\"view.php?id=$cm->id\">$glossary->name</A> -> $stredit", "form.text",
+                        "", true, "", navmenu($course, $cm));
+    
+    print_heading($glossary->name);
+    
     if ($e) {
         //We are updating an entry, so we compare current session user with
         //existing entry user to avoid some potential problems if secureforms=off
@@ -123,7 +129,7 @@ if ( $confirm ) {
 
         if ( $permissiongranted ) {
             $newentry->attachment = $_FILES["attachment"];
-            if ($newfilename = glossary_add_attachment($newentry, $newentry->attachment)) {
+            if ($newfilename = glossary_add_attachment($newentry, 'attachment')) {
                 $newentry->attachment = $newfilename;
             } else {
                 unset($newentry->attachment);
@@ -133,12 +139,13 @@ if ( $confirm ) {
                 error("Could not update your glossary");
             } else {
                 add_to_log($course->id, "glossary", "update entry", "view.php?id=$cm->id&mode=entry&hook=$newentry->id", $newentry->id,$cm->id);
+                notify(get_string('entryupdated','glossary'));
             }
         } else {
             error("Could not update this glossary entry because this concept already exist.");
         }
     } else {
-
+    
         $newentry->userid = $USER->id;
         $newentry->timecreated = $timenow;
         $newentry->sourceglossaryid = 0;
@@ -156,13 +163,14 @@ if ( $confirm ) {
             } else {
                 $e = $newentry->id;
                 $newentry->attachment = $_FILES["attachment"];
-                if ($newfilename = glossary_add_attachment($newentry, $newentry->attachment)) {
+                if ($newfilename = glossary_add_attachment($newentry, 'attachment')) {
                     $newentry->attachment = $newfilename;
                 } else {
                      unset($newentry->attachment);
                 }
                 set_field("glossary_entries", "attachment", $newfilename, "id", $newentry->id);
                 add_to_log($course->id, "glossary", "add entry", "view.php?id=$cm->id&mode=entry&hook=$newentry->id", $newentry->id,$cm->id);
+                notify(get_string('entrysaved','glossary'));
             }
         } else {
             error("Could not insert this glossary entry because this concept already exist.");
@@ -196,8 +204,8 @@ if ( $confirm ) {
             }
         }
     }
-
-    redirect("view.php?id=$cm->id&mode=entry&hook=$newentry->id");
+    print_continue("view.php?id=$cm->id&mode=entry&hook=$newentry->id");
+    print_footer();
     die;
 } else {
     if ($e) {
index 4b6e3a275baaddfad358b9fcd07f57d2fe6de252..d1b90e4086349634a4d691437606473ebea8d86a 100644 (file)
@@ -3,9 +3,9 @@
 <tr>
     <td align="right" valign="top" width="30%"><p><b><?php print_string("filetoimport","glossary") ?>:</b></p></td>
     <td width="70%">
-    <input type="hidden" name="MAX_FILE_SIZE" value="<?php echo get_max_upload_file_size() ?>" />
-    <input type="file" name="file" size="40"> <br />
     <?php 
+       require_once($CFG->dirroot.'/lib/uploadlib.php');
+       upload_print_form_fragment(1,array('file'),null,false,null,0,0);
        helpbutton("filetoimport", get_string("filetoimport", "glossary"), "glossary"); 
        print_string("maxsize", "", display_size(get_max_upload_file_size())); 
     ?>
index 2e689877add2cc4fedf88beb5a9e3a8261e15ed1..32fa5ad454b517c0f59dc4737f726b53b296c7a0 100644 (file)
     $form = data_submitted();
     $file = $_FILES["file"];
 
+    require_once($CFG->dirroot.'/lib/uploadlib.php');
+    $um = new upload_manager('file',false,false,$course,false,0);
+
+    if (!$um->preprocess_files()) {
+        print_continue('import.php?id='.$id);
+        print_footer();
+        die();
+    }
+
     if ($xml = glossary_read_imported_file($file['tmp_name']) ) {
 
         $importedentries = 0;
index 1b89d373e815a8898a6744a7fa355bd985238848..030edac334b4f5e6100c58d05aa00f660b861f59 100644 (file)
@@ -1010,6 +1010,8 @@ function glossary_move_attachments($entry, $glossaryid) {
 
     global $CFG;
 
+    require_once($CFG->dirroot.'/lib/uploadlib.php');
+
     $return = true;
 
     if ($entries = get_records_select("glossary_entries", "glossaryid = '$entry->id' AND attachment <> ''")) {
@@ -1021,50 +1023,43 @@ function glossary_move_attachments($entry, $glossaryid) {
                 $newentry = $oldentry;
                 $newentry->glossaryid = $glossaryid;
                 $newentrydir = "$CFG->dataroot/".glossary_file_area_name($newentry);
+                $files = get_directory_list($oldentrydir); // get it before we rename it.
                 if (! @rename($oldentrydir, $newentrydir)) {
                     $return = false;
                 }
+                foreach ($files as $file) {
+                    // this is not tested as I can't find anywhere that calls this function, grepping the source.
+                    clam_change_log($oldentrydir.'/'.$file,$newentrydir.'/'.$file);                    
+                }
             }
         }
     }
     return $return;
 }
 
-function glossary_add_attachment($entry, $newfile) {
+function glossary_add_attachment($entry, $inputname) {
 // $entry is a full entry record, including course and glossary
 // $newfile is a full upload array from $_FILES
 // If successful, this function returns the name of the file
 
     global $CFG;
 
-    if (empty($newfile['name'])) {
-        return "";
+    if (!$glossary = get_record("glossary","id",$entry->glossaryid)) {
+        return false;
+    }
+    
+    if (!$course = get_record("course","id",$glossary->course)) {
+        return false;
     }
 
-    $newfile_name = clean_filename($newfile['name']);
-
-    if (valid_uploaded_file($newfile)) {
-        if (! $newfile_name) {
-            notify("This file had a wierd filename and couldn't be uploaded");
-
-        } else if (! $dir = glossary_file_area($entry)) {
-            notify("Attachment could not be stored");
-            $newfile_name = "";
+    require_once($CFG->dirroot.'/lib/uploadlib.php');
+    $um = new upload_manager($inputname,true,false,$course,false,0);
+    $dir = glossary_file_area_name($entry);
 
-        } else {
-            if (move_uploaded_file($newfile['tmp_name'], "$dir/$newfile_name")) {
-                chmod("$dir/$newfile_name", $CFG->directorypermissions);
-                glossary_delete_old_attachments($entry, $newfile_name);
-            } else {
-                notify("An error happened while saving the file on the server");
-                $newfile_name = "";
-            }
-        }
-    } else {
-        $newfile_name = "";
+    if ($um->process_file_uploads($dir)) {
+        return $um->get_new_filename();
     }
-
-    return $newfile_name;
+    // upload manager will take care of errors.
 }
 
 function glossary_print_attachments($entry, $return=NULL, $align="left") {
index 3fe5d1aac12fdd6339c87f76cff624859d698e80..e0a38e410c34fd753711e418d6bde878518c57d6 100644 (file)
 
         case "upload":
             html_header($course, $wdir);
-
-            if (!empty($_FILES['userfile'])) {
-                $userfile = $_FILES['userfile'];
-            } else {
-                $save = false;
-            }
+            require_once($CFG->dirroot.'/lib/uploadlib.php');
+                
             if (!empty($save)) {
-                if (!is_uploaded_file($userfile['tmp_name']) or $userfile['size'] == 0) {
-                    notify(get_string("uploadnofilefound"));
-                } else {
-                    $userfile_name = clean_filename($userfile['name']);
-                    if ($userfile_name) {
-                        $newfile = "$basedir$wdir/$userfile_name";
-                        if (move_uploaded_file($userfile['tmp_name'], $newfile)) {
-                            chmod($newfile, 0666);
-                            $a = NULL;
-                            $a->file = "$userfile_name (".$userfile['type'].")";
-                            $a->directory = $wdir;
-                            print_string("uploadedfileto", "", $a);
-                        } else {
-                            notify(get_string("uploadproblem", "", $userfile_name));
-                        }
-                    }
+                $um = new upload_manager('userfile',false,false,$course,false,0);
+                $dir = "$basedir$wdir";
+                if ($um->process_file_uploads($dir)) {
+                    notify(get_string('uploadedfile'));
                 }
+                // um will take care of error reporting.
                 displaydir($wdir);
-
             } else {
                 $upload_max_filesize = get_max_upload_file_size($CFG->maxbytes);
                 $filesize = display_size($upload_max_filesize);
                 echo "<p>$struploadafile ($strmaxsize) --> <b>$wdir</b>";
                 echo "<table><tr><td colspan=\"2\">";
                 echo "<form enctype=\"multipart/form-data\" method=\"post\" action=\"".$ME."\">";
-                echo " <input type=\"hidden\" name=MAX_FILE_SIZE value=\"$upload_max_filesize\" />";
+                upload_print_form_fragment(1,array('userfile'),null,false,null,$course->maxbytes,0,false);
                 echo " <input type=\"hidden\" name=\"id\" value=$id />";
                 echo " <input type=\"hidden\" name=\"wdir\" value=$wdir />";
                 echo " <input type=\"hidden\" name=\"action\" value=\"upload\" />";
-                echo " <input name=\"userfile\" type=\"file\" size=\"60\" />";
                 echo " </td><tr><td width=\"10\">";
                 echo " <input type=\"submit\" name=\"save\" value=\"$struploadthisfile\" />";
                 echo "</form>";
@@ -663,6 +646,7 @@ function print_cell($alignment="center", $text="&nbsp;") {
 }
 
 function displaydir ($wdir) {
+
 //  $wdir == / or /a or /a/b/c/d  etc
 
     global $basedir;
@@ -742,7 +726,6 @@ function displaydir ($wdir) {
         }
     }
 
-
     if (!empty($filelist)) {
         asort($filelist);
         foreach ($filelist as $file) {
index 0b402be3305c6d6f81296197be785caad178c709..ae42a919d53c0675b64d142d411ca5d71b0833b6 100755 (executable)
 
         case "upload":
             html_header($course, $wdir);
-
-            if (!empty($_FILES['userfile'])) {
-                $userfile = $_FILES['userfile'];
-            } else {
-                $save = false;
-            }
+            require_once($CFG->dirroot.'/lib/uploadlib.php');
+                
             if (!empty($save)) {
-                if (!is_uploaded_file($userfile['tmp_name']) or $userfile['size'] == 0) {
-                    notify(get_string("uploadnofilefound"));
-                } else {
-                    $userfile_name = clean_filename($userfile['name']);
-                    if ($userfile_name) {
-                        $newfile = "$basedir$wdir/$userfile_name";
-                        if (move_uploaded_file($userfile['tmp_name'], $newfile)) {
-                            chmod($newfile, 0666);
-                            $a = NULL;
-                            $a->file = "$userfile_name (".$userfile['type'].")";
-                            $a->directory = $wdir;
-                            print_string("uploadedfileto", "", $a);
-                        } else {
-                            notify(get_string("uploadproblem", "", $userfile_name));
-                        }
-                    }
+                $um = new upload_manager('userfile',false,false,$course,false,0);
+                $dir = "$basedir$wdir";
+                if ($um->process_file_uploads($dir)) {
+                    notify(get_string('uploadedfile'));
                 }
+                // um will take care of error reporting.
                 displaydir($wdir);
-                    
             } else {
                 $upload_max_filesize = get_max_upload_file_size($CFG->maxbytes);
                 $filesize = display_size($upload_max_filesize);
                 echo "<p>$struploadafile ($strmaxsize) --> <b>$wdir</b>";
                 echo "<table><tr><td colspan=\"2\">";
                 echo "<form enctype=\"multipart/form-data\" method=\"post\" action=\"".$ME."\">";
-                echo " <input type=\"hidden\" name=MAX_FILE_SIZE value=\"$upload_max_filesize\" />";
                 echo " <input type=\"hidden\" name=\"id\" value=$id />";
                 echo " <input type=\"hidden\" name=\"wdir\" value=$wdir />";
                 echo " <input type=\"hidden\" name=\"action\" value=\"upload\" />";
-                echo " <input name=\"userfile\" type=\"file\" size=\"60\" />";
+                upload_print_form_fragment(1,array('userfile'),null,false,null,$course->maxbytes,0,false);
                 echo " </td><tr><td width=\"10\">";
                 echo " <input type=\"submit\" name=\"save\" value=\"$struploadthisfile\" />";
                 echo "</form>";