1 | <?php |
||||||
2 | /* For licensing terms, see /license.txt */ |
||||||
3 | |||||||
4 | /** |
||||||
5 | * Functions and main code for the download folder feature. |
||||||
6 | * |
||||||
7 | * @todo use ids instead of the path like the document tool |
||||||
8 | * |
||||||
9 | * @package chamilo.work |
||||||
10 | */ |
||||||
11 | require_once __DIR__.'/../inc/global.inc.php'; |
||||||
12 | |||||||
13 | api_protect_course_script(true); |
||||||
14 | |||||||
15 | $workId = isset($_GET['id']) ? (int) $_GET['id'] : 0; |
||||||
16 | |||||||
17 | $current_course_tool = TOOL_STUDENTPUBLICATION; |
||||||
18 | $_course = api_get_course_info(); |
||||||
19 | |||||||
20 | if (empty($_course)) { |
||||||
21 | api_not_allowed(); |
||||||
22 | } |
||||||
23 | |||||||
24 | require_once 'work.lib.php'; |
||||||
25 | |||||||
26 | $work_data = get_work_data_by_id($workId); |
||||||
27 | $groupId = api_get_group_id(); |
||||||
28 | |||||||
29 | if (empty($work_data)) { |
||||||
30 | api_not_allowed(); |
||||||
31 | } |
||||||
32 | |||||||
33 | // Prevent some stuff. |
||||||
34 | if (empty($path)) { |
||||||
35 | $path = '/'; |
||||||
36 | } |
||||||
37 | |||||||
38 | if (empty($_course) || empty($_course['path'])) { |
||||||
39 | api_not_allowed(); |
||||||
40 | } |
||||||
41 | |||||||
42 | $sys_course_path = api_get_path(SYS_COURSE_PATH); |
||||||
43 | |||||||
44 | // Creating a ZIP file |
||||||
45 | $temp_zip_file = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().'.zip'; |
||||||
46 | $zip_folder = new PclZip($temp_zip_file); |
||||||
47 | |||||||
48 | $tbl_student_publication = Database::get_course_table(TABLE_STUDENT_PUBLICATION); |
||||||
49 | $prop_table = Database::get_course_table(TABLE_ITEM_PROPERTY); |
||||||
50 | $tableUser = Database::get_main_table(TABLE_MAIN_USER); |
||||||
51 | |||||||
52 | // Put the files in the zip |
||||||
53 | // 2 possibilities: admins get all files and folders in the selected folder (except for the deleted ones) |
||||||
54 | // normal users get only visible files that are in visible folders |
||||||
55 | |||||||
56 | //admins are allowed to download invisible files |
||||||
57 | $files = []; |
||||||
58 | $course_id = api_get_course_int_id(); |
||||||
59 | $sessionId = api_get_session_id(); |
||||||
60 | |||||||
61 | $sessionCondition = api_get_session_condition($sessionId, true, false, 'props.session_id'); |
||||||
62 | |||||||
63 | $filenameCondition = null; |
||||||
64 | if (array_key_exists('filename', $work_data)) { |
||||||
65 | $filenameCondition = ", filename"; |
||||||
66 | } |
||||||
67 | |||||||
68 | $groupIid = 0; |
||||||
69 | if ($groupId) { |
||||||
70 | $groupInfo = GroupManager::get_group_properties($groupId); |
||||||
71 | $groupIid = $groupInfo['iid']; |
||||||
72 | } |
||||||
73 | |||||||
74 | if (api_is_allowed_to_edit() || api_is_coach()) { |
||||||
75 | //Search for all files that are not deleted => visibility != 2 |
||||||
76 | $sql = "SELECT DISTINCT |
||||||
77 | url, |
||||||
78 | title, |
||||||
79 | description, |
||||||
80 | insert_user_id, |
||||||
81 | sent_date, |
||||||
82 | contains_file |
||||||
83 | $filenameCondition |
||||||
84 | FROM $tbl_student_publication AS work |
||||||
85 | INNER JOIN $prop_table AS props |
||||||
86 | ON (work.id = props.ref AND props.c_id = work.c_id) |
||||||
87 | INNER JOIN $tableUser as u |
||||||
88 | ON ( |
||||||
89 | work.user_id = u.user_id |
||||||
90 | ) |
||||||
91 | WHERE |
||||||
92 | props.tool = 'work' AND |
||||||
93 | props.c_id = $course_id AND |
||||||
94 | work.c_id = $course_id AND |
||||||
95 | work.parent_id = $workId AND |
||||||
96 | work.filetype = 'file' AND |
||||||
97 | props.visibility <> '2' AND |
||||||
98 | work.active IN (0, 1) AND |
||||||
99 | work.post_group_id = $groupIid |
||||||
100 | $sessionCondition |
||||||
101 | "; |
||||||
102 | } else { |
||||||
103 | $courseInfo = api_get_course_info(); |
||||||
104 | protectWork($courseInfo, $workId); |
||||||
105 | $userCondition = ''; |
||||||
106 | |||||||
107 | // All users |
||||||
108 | if ($courseInfo['show_score'] == 0) { |
||||||
109 | // Do another filter |
||||||
110 | } else { |
||||||
111 | // Only teachers |
||||||
112 | $userCondition = " AND props.insert_user_id = ".api_get_user_id(); |
||||||
113 | } |
||||||
114 | |||||||
115 | //for other users, we need to create a zipfile with only visible files and folders |
||||||
116 | $sql = "SELECT DISTINCT |
||||||
117 | url, |
||||||
118 | title, |
||||||
119 | description, |
||||||
120 | insert_user_id, |
||||||
121 | sent_date, |
||||||
122 | contains_file |
||||||
123 | $filenameCondition |
||||||
124 | FROM $tbl_student_publication AS work |
||||||
125 | INNER JOIN $prop_table AS props |
||||||
126 | ON ( |
||||||
127 | props.c_id = work.c_id AND |
||||||
128 | work.id = props.ref |
||||||
129 | ) |
||||||
130 | WHERE |
||||||
131 | props.c_id = $course_id AND |
||||||
132 | work.c_id = $course_id AND |
||||||
133 | props.tool = 'work' AND |
||||||
134 | work.accepted = 1 AND |
||||||
135 | work.active = 1 AND |
||||||
136 | work.parent_id = $workId AND |
||||||
137 | work.filetype = 'file' AND |
||||||
138 | props.visibility = '1' AND |
||||||
139 | work.post_group_id = $groupIid |
||||||
140 | $userCondition |
||||||
141 | "; |
||||||
142 | } |
||||||
143 | $query = Database::query($sql); |
||||||
144 | |||||||
145 | //add tem to the zip file |
||||||
146 | while ($not_deleted_file = Database::fetch_assoc($query)) { |
||||||
147 | $userInfo = api_get_user_info($not_deleted_file['insert_user_id']); |
||||||
148 | $insert_date = api_get_local_time($not_deleted_file['sent_date']); |
||||||
149 | $insert_date = str_replace([':', '-', ' '], '_', $insert_date); |
||||||
150 | |||||||
151 | $title = basename($not_deleted_file['title']); |
||||||
152 | if (!empty($filenameCondition)) { |
||||||
153 | if (isset($not_deleted_file['filename']) && !empty($not_deleted_file['filename'])) { |
||||||
154 | $title = $not_deleted_file['filename']; |
||||||
155 | } |
||||||
156 | } |
||||||
157 | $filename = $insert_date.'_'.$userInfo['username'].'_'.$title; |
||||||
158 | $filename = api_replace_dangerous_char($filename); |
||||||
159 | // File exists |
||||||
160 | if (file_exists($sys_course_path.$_course['path'].'/'.$not_deleted_file['url']) && |
||||||
161 | !empty($not_deleted_file['url']) |
||||||
162 | ) { |
||||||
163 | $files[basename($not_deleted_file['url'])] = $filename; |
||||||
164 | $addStatus = $zip_folder->add( |
||||||
165 | $sys_course_path.$_course['path'].'/'.$not_deleted_file['url'], |
||||||
166 | PCLZIP_OPT_REMOVE_PATH, |
||||||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||||||
167 | $sys_course_path.$_course['path'].'/work', |
||||||
168 | PCLZIP_CB_PRE_ADD, |
||||||
0 ignored issues
–
show
|
|||||||
169 | 'my_pre_add_callback' |
||||||
170 | ); |
||||||
171 | } else { |
||||||
172 | // Convert texts in html files |
||||||
173 | $filename = trim($filename).".html"; |
||||||
174 | $work_temp = api_get_path(SYS_ARCHIVE_PATH).api_get_unique_id().'_'.$filename; |
||||||
175 | file_put_contents($work_temp, $not_deleted_file['description']); |
||||||
176 | $files[basename($work_temp)] = $filename; |
||||||
177 | $addStatus = $zip_folder->add( |
||||||
178 | $work_temp, |
||||||
179 | PCLZIP_OPT_REMOVE_PATH, |
||||||
180 | api_get_path(SYS_ARCHIVE_PATH), |
||||||
181 | PCLZIP_CB_PRE_ADD, |
||||||
182 | 'my_pre_add_callback' |
||||||
183 | ); |
||||||
184 | @unlink($work_temp); |
||||||
0 ignored issues
–
show
It seems like you do not handle an error condition for
unlink() . This can introduce security issues, and is generally not recommended.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
If you suppress an error, we recommend checking for the error condition explicitly: // For example instead of
@mkdir($dir);
// Better use
if (@mkdir($dir) === false) {
throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
![]() |
|||||||
185 | } |
||||||
186 | } |
||||||
187 | |||||||
188 | if (!empty($files)) { |
||||||
189 | $fileName = api_replace_dangerous_char($work_data['title']); |
||||||
190 | // Logging |
||||||
191 | Event::event_download($fileName.'.zip (folder)'); |
||||||
0 ignored issues
–
show
The method
event_download() does not exist on Event .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed. ![]() |
|||||||
192 | |||||||
193 | //start download of created file |
||||||
194 | $name = $fileName.'.zip'; |
||||||
195 | |||||||
196 | if (Security::check_abs_path($temp_zip_file, api_get_path(SYS_ARCHIVE_PATH))) { |
||||||
197 | DocumentManager::file_send_for_download($temp_zip_file, true, $name); |
||||||
198 | @unlink($temp_zip_file); |
||||||
199 | exit; |
||||||
200 | } |
||||||
201 | } else { |
||||||
202 | exit; |
||||||
203 | } |
||||||
204 | |||||||
205 | /* Extra function (only used here) */ |
||||||
206 | function my_pre_add_callback($p_event, &$p_header) |
||||||
207 | { |
||||||
208 | global $files; |
||||||
209 | if (isset($files[basename($p_header['stored_filename'])])) { |
||||||
210 | $p_header['stored_filename'] = $files[basename($p_header['stored_filename'])]; |
||||||
211 | |||||||
212 | return 1; |
||||||
213 | } |
||||||
214 | |||||||
215 | return 0; |
||||||
216 | } |
||||||
217 | |||||||
218 | /** |
||||||
219 | * Return the difference between two arrays, as an array of those key/values |
||||||
220 | * Use this as array_diff doesn't give the. |
||||||
221 | * |
||||||
222 | * @param array $arr1 first array |
||||||
223 | * @param array $arr2 second array |
||||||
224 | * |
||||||
225 | * @return array difference between the two arrays |
||||||
226 | */ |
||||||
227 | function diff($arr1, $arr2) |
||||||
228 | { |
||||||
229 | $res = []; |
||||||
230 | $r = 0; |
||||||
231 | foreach ($arr1 as $av) { |
||||||
232 | if (!in_array($av, $arr2)) { |
||||||
233 | $res[$r] = $av; |
||||||
234 | $r++; |
||||||
235 | } |
||||||
236 | } |
||||||
237 | |||||||
238 | return $res; |
||||||
239 | } |
||||||
240 |