diff --git a/.htaccess b/.htaccess index 1621a1f5d9..e334d1797c 100755 --- a/.htaccess +++ b/.htaccess @@ -91,3 +91,25 @@ AddType application/font-woff .woff .woff2 ExpiresActive On ExpiresByType application/font-woff "access plus 1 month" + +# Force SSL/HTTPS +# We recommend you place this block in your VirtualHost config rather +# than uncommenting it below. However, if you have no other way, +# feel free to uncomment it, but please remember that this file will +# be overwritten during your next Chamilo update. +# Also note this will only work if you have an SSL certificate +# configured elsewhere in your Apache configuration. + +#RewriteCond %{HTTPS} !=on +#RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L] +# +# Header always set Content-Security-Policy "upgrade-insecure-requests;" +# + +# Disallow direct access to /main/inc/lib/javascript/bigupload/files +RedirectMatch 403 ^/main/inc/lib/javascript/bigupload/files + +# Disallow MIME sniffing to prevent XSS from unknown/incorrect file extensions + + Header always set X-Content-Type-Options nosniff + diff --git a/main/admin/configure_extensions.php b/main/admin/configure_extensions.php index d7d6186db2..ef06c053f1 100755 --- a/main/admin/configure_extensions.php +++ b/main/admin/configure_extensions.php @@ -158,7 +158,11 @@ Display::display_header($nameTool);
addElement('text', 'host', get_lang('Host')); + if (api_get_configuration_value('webservice_remote_ppt2png_enable') == true) { + $form->addElement('text', 'host', get_lang('Host')); + } else { + $form->addElement('text', 'host', [get_lang('Host'),'Remote host disabled - set webservice_remote_ppt2png_enable setting to true in configuration.php to enable']); + } //$form -> addElement('html','

'); $form->addElement('text', 'port', get_lang('Port')); //$form -> addElement('html','

'); diff --git a/main/inc/ajax/document.ajax.php b/main/inc/ajax/document.ajax.php index 108ffa0f6e..85a2dd10ad 100755 --- a/main/inc/ajax/document.ajax.php +++ b/main/inc/ajax/document.ajax.php @@ -27,117 +27,231 @@ switch ($action) { break; case 'upload_file': api_protect_course_script(true); - // User access same as upload.php - $is_allowed_to_edit = api_is_allowed_to_edit(null, true); - $sessionId = api_get_session_id(); + if (isset($_REQUEST['chunkAction']) && 'send' === $_REQUEST['chunkAction']) { + // It uploads the files in chunks + if (!empty($_FILES)) { + $tempDirectory = api_get_path(SYS_ARCHIVE_PATH); + $files = $_FILES['files']; + $fileList = []; + foreach ($files as $name => $array) { + $counter = 0; + foreach ($array as $data) { + $fileList[$counter][$name] = $data; + $counter++; + } + } + if (!empty($fileList)) { + foreach ($fileList as $n => $file) { + $tmpFile = disable_dangerous_file( + api_replace_dangerous_char($file['name']) + ); + + file_put_contents( + $tempDirectory.$tmpFile, + fopen($file['tmp_name'], 'r'), + FILE_APPEND + ); + } + } + } + echo json_encode([ + 'files' => $_FILES, + 'errorStatus' => 0, + ]); + exit; + } else { + // User access same as upload.php + $is_allowed_to_edit = api_is_allowed_to_edit(null, true); - if (!$is_allowed_to_edit && $sessionId && $_REQUEST['curdirpath'] == "/basic-course-documents__{$sessionId}__0") { - $session = SessionManager::fetch($sessionId); + $sessionId = api_get_session_id(); - if (!empty($session) && $session['session_admin_id'] == api_get_user_id()) { - $is_allowed_to_edit = true; + if (!$is_allowed_to_edit && $sessionId && $_REQUEST['curdirpath'] == "/basic-course-documents__{$sessionId}__0") { + $session = SessionManager::fetch($sessionId); + + if (!empty($session) && $session['session_admin_id'] == api_get_user_id()) { + $is_allowed_to_edit = true; + } } - } - // This needs cleaning! - if (api_get_group_id()) { - $groupInfo = GroupManager::get_group_properties(api_get_group_id()); - // Only course admin or group members allowed - if ($is_allowed_to_edit || GroupManager::is_user_in_group(api_get_user_id(), $groupInfo)) { - if (!GroupManager::allowUploadEditDocument(api_get_user_id(), api_get_course_int_id(), $groupInfo)) { + // This needs cleaning! + if (api_get_group_id()) { + $groupInfo = GroupManager::get_group_properties(api_get_group_id()); + // Only course admin or group members allowed + if ($is_allowed_to_edit || GroupManager::is_user_in_group(api_get_user_id(), $groupInfo)) { + if (!GroupManager::allowUploadEditDocument( + api_get_user_id(), + api_get_course_int_id(), + $groupInfo + )) { + exit; + } + } else { exit; } + } elseif ($is_allowed_to_edit || + DocumentManager::is_my_shared_folder(api_get_user_id(), $_REQUEST['curdirpath'], api_get_session_id()) + ) { + // ?? } else { + // No course admin and no group member... exit; } - } elseif ($is_allowed_to_edit || - DocumentManager::is_my_shared_folder(api_get_user_id(), $_REQUEST['curdirpath'], api_get_session_id()) - ) { - // ?? - } else { - // No course admin and no group member... - exit; - } - $directoryParentId = isset($_POST['directory_parent_id']) ? $_POST['directory_parent_id'] : 0; - $currentDirectory = ''; - if (empty($directoryParentId)) { - $currentDirectory = isset($_REQUEST['curdirpath']) ? $_REQUEST['curdirpath'] : ''; - } else { - $documentData = DocumentManager::get_document_data_by_id($directoryParentId, api_get_course_id()); - if ($documentData) { - $currentDirectory = $documentData['path']; + $directoryParentId = isset($_POST['directory_parent_id']) ? (int) $_POST['directory_parent_id'] : 0; + $currentDirectory = ''; + if (empty($directoryParentId)) { + $currentDirectory = $_REQUEST['curdirpath'] ?? ''; + } else { + $documentData = DocumentManager::get_document_data_by_id($directoryParentId, api_get_course_id()); + if ($documentData) { + $currentDirectory = $documentData['path']; + } } - } - - $ifExists = isset($_POST['if_exists']) ? $_POST['if_exists'] : ''; - $unzip = isset($_POST['unzip']) ? 1 : 0; - - if (empty($ifExists)) { - $fileExistsOption = api_get_setting('document_if_file_exists_option'); - $defaultFileExistsOption = 'rename'; - if (!empty($fileExistsOption)) { - $defaultFileExistsOption = $fileExistsOption; + if (empty($currentDirectory)) { + $currentDirectory = DIRECTORY_SEPARATOR; } - } else { - $defaultFileExistsOption = $ifExists; - } + $ifExists = $_POST['if_exists'] ?? ''; + $unzip = isset($_POST['unzip']) ? 1 : 0; - if (!empty($_FILES)) { - $files = $_FILES['files']; - $fileList = []; - foreach ($files as $name => $array) { - $counter = 0; - foreach ($array as $data) { - $fileList[$counter][$name] = $data; - $counter++; + if (empty($ifExists)) { + $fileExistsOption = api_get_setting('document_if_file_exists_option'); + $defaultFileExistsOption = 'rename'; + if (!empty($fileExistsOption)) { + $defaultFileExistsOption = $fileExistsOption; } + } else { + $defaultFileExistsOption = $ifExists; } - $resultList = []; - foreach ($fileList as $file) { - $globalFile = []; - $globalFile['files'] = $file; - $result = DocumentManager::upload_document( - $globalFile, - $currentDirectory, - '', - '', // comment - $unzip, - $defaultFileExistsOption, - false, - false, - 'files' - ); - - $json = []; - if (!empty($result) && is_array($result)) { - $json['name'] = api_htmlentities($result['title']); - $json['link'] = Display::url( - api_htmlentities($result['title']), - api_htmlentities($result['url']), - ['target' => '_blank'] - ); - $json['url'] = $result['url']; - $json['size'] = format_file_size($file['size']); - $json['type'] = api_htmlentities($file['type']); - $json['result'] = Display::return_icon( - 'accept.png', - get_lang('Uploaded') + if (!empty($_FILES)) { + $files = $_FILES['files']; + + $fileList = []; + foreach ($files as $name => $array) { + $counter = 0; + foreach ($array as $data) { + $fileList[$counter][$name] = $data; + $counter++; + } + } + + $resultList = []; + foreach ($fileList as $file) { + if (isset($_REQUEST['chunkAction']) && 'done' === $_REQUEST['chunkAction']) { + // to rename and move the finished file + $tmpFile = disable_dangerous_file( + api_replace_dangerous_char($file['name']) + ); + $chunkedFile = api_get_path(SYS_ARCHIVE_PATH).$tmpFile; + $file['tmp_name'] = $chunkedFile; + $file['size'] = filesize($chunkedFile); + $file['copy_file'] = true; + } + + $globalFile = []; + $globalFile['files'] = $file; + $result = DocumentManager::upload_document( + $globalFile, + $currentDirectory, + '', + '', // comment + $unzip, + $defaultFileExistsOption, + false, + false, + 'files' ); - } else { - $json['name'] = isset($file['name']) ? $file['name'] : get_lang('Unknown'); - $json['url'] = ''; - $json['error'] = get_lang('Error'); + + $json = []; + if (!empty($result) && is_array($result)) { + $json['name'] = api_htmlentities($result['title']); + $json['link'] = Display::url( + api_htmlentities($result['title']), + api_htmlentities($result['url']), + ['target' => '_blank'] + ); + $json['url'] = $result['url']; + $json['size'] = format_file_size($file['size']); + $json['type'] = api_htmlentities($file['type']); + $json['result'] = Display::return_icon( + 'accept.png', + get_lang('Uploaded') + ); + } else { + $json['name'] = $file['name'] ?? get_lang('Unknown'); + $json['url'] = ''; + $json['error'] = get_lang('Error'); + } + $resultList[] = $json; } - $resultList[] = $json; + + echo json_encode(['files' => $resultList]); + exit; } + } + break; + case 'ck_uploadimage': + api_protect_course_script(true); + + // it comes from uploaimage drag and drop ckeditor + $isCkUploadImage = ($_COOKIE['ckCsrfToken'] == $_POST['ckCsrfToken']); - echo json_encode(['files' => $resultList]); + if (!$isCkUploadImage) { + exit; } + + $data = []; + $fileUpload = $_FILES['upload']; + $currentDirectory = Security::remove_XSS($_REQUEST['curdirpath']); + $isAllowedToEdit = api_is_allowed_to_edit(null, true); + if ($isAllowedToEdit) { + $globalFile = ['files' => $fileUpload]; + $result = DocumentManager::upload_document( + $globalFile, + $currentDirectory, + '', + '', + 0, + 'rename', + false, + false, + 'files' + ); + if ($result) { + $relativeUrl = str_replace(api_get_path(WEB_PATH), '/', $result['direct_url']); + $data = [ + 'uploaded' => 1, + 'fileName' => $fileUpload['name'], + 'url' => $relativeUrl, + ]; + } + } else { + $userId = api_get_user_id(); + $syspath = UserManager::getUserPathById($userId, 'system').'my_files'.$currentDirectory; + if (!is_dir($syspath)) { + mkdir($syspath, api_get_permissions_for_new_directories(), true); + } + $webpath = UserManager::getUserPathById($userId, 'web').'my_files'.$currentDirectory; + $fileUploadName = $fileUpload['name']; + if (file_exists($syspath.$fileUploadName)) { + $extension = pathinfo($fileUploadName, PATHINFO_EXTENSION); + $fileName = pathinfo($fileUploadName, PATHINFO_FILENAME); + $suffix = '_'.uniqid(); + $fileUploadName = $fileName.$suffix.'.'.$extension; + } + if (move_uploaded_file($fileUpload['tmp_name'], $syspath.$fileUploadName)) { + $url = $webpath.$fileUploadName; + $relativeUrl = str_replace(api_get_path(WEB_PATH), '/', $url); + $data = [ + 'uploaded' => 1, + 'fileName' => $fileUploadName, + 'url' => $relativeUrl, + ]; + } + } + echo json_encode($data); exit; - break; case 'document_preview': $courseInfo = api_get_course_info_by_id($_REQUEST['course_id']); if (!empty($courseInfo) && is_array($courseInfo)) { diff --git a/main/inc/ajax/dropbox.ajax.php b/main/inc/ajax/dropbox.ajax.php index bb78955012..b97539d62f 100644 --- a/main/inc/ajax/dropbox.ajax.php +++ b/main/inc/ajax/dropbox.ajax.php @@ -11,72 +11,116 @@ $action = $_REQUEST['a']; switch ($action) { case 'upload_file': api_protect_course_script(true); - // User access same as upload.php - $is_allowed_to_edit = api_is_allowed_to_edit(null, true); - $recipients = isset($_POST['recipients']) ? $_POST['recipients'] : ''; - $id = isset($_GET['id']) ? (int) $_GET['id'] : 0; + if (isset($_REQUEST['chunkAction']) && 'send' === $_REQUEST['chunkAction']) { + // It uploads the files in chunks + if (!empty($_FILES)) { + $tempDirectory = api_get_path(SYS_ARCHIVE_PATH); + $files = $_FILES['files']; + $fileList = []; + foreach ($files as $name => $array) { + $counter = 0; + foreach ($array as $data) { + $fileList[$counter][$name] = $data; + $counter++; + } + } + if (!empty($fileList)) { + foreach ($fileList as $n => $file) { + $tmpFile = disable_dangerous_file( + api_replace_dangerous_char($file['name']) + ); - if (empty($recipients) && empty($id)) { - $resultList[] = ['error' => get_lang('YouMustSelectAtLeastOneDestinee')]; - echo json_encode(['files' => $resultList]); + file_put_contents( + $tempDirectory.$tmpFile, + fopen($file['tmp_name'], 'r'), + FILE_APPEND + ); + } + } + } + echo json_encode([ + 'files' => $_FILES, + 'errorStatus' => 0, + ]); exit; - } - $work = null; - if (!empty($id)) { - $work = new Dropbox_SentWork($id); - if (empty($work)) { - $resultList[] = ['error' => get_lang('Error')]; + } else { + + // User access same as upload.php + $is_allowed_to_edit = api_is_allowed_to_edit(null, true); + + $recipients = isset($_POST['recipients']) ? $_POST['recipients'] : ''; + $id = isset($_GET['id']) ? (int) $_GET['id'] : 0; + + if (empty($recipients) && empty($id)) { + $resultList[] = ['error' => get_lang('YouMustSelectAtLeastOneDestinee')]; echo json_encode(['files' => $resultList]); exit; } - } - - if (!empty($_FILES)) { - $files = $_FILES['files']; - $fileList = []; - foreach ($files as $name => $array) { - $counter = 0; - foreach ($array as $data) { - $fileList[$counter][$name] = $data; - $counter++; + $work = null; + if (!empty($id)) { + $work = new Dropbox_SentWork($id); + if (empty($work)) { + $resultList[] = ['error' => get_lang('Error')]; + echo json_encode(['files' => $resultList]); + exit; } } - $resultList = []; - foreach ($fileList as $file) { - $globalFile = []; - $globalFile['files'] = $file; - /** @var Dropbox_SentWork $result */ - $result = store_add_dropbox($file, $work); + if (!empty($_FILES)) { + $files = $_FILES['files']; + $fileList = []; + foreach ($files as $name => $array) { + $counter = 0; + foreach ($array as $data) { + $fileList[$counter][$name] = $data; + $counter++; + } + } + + $resultList = []; + foreach ($fileList as $file) { + if (isset($_REQUEST['chunkAction']) && 'done' === $_REQUEST['chunkAction']) { + // to rename and move the finished file + $chunkedFile = api_get_path(SYS_ARCHIVE_PATH).$file['name']; + $file['tmp_name'] = $chunkedFile; + $file['size'] = filesize($chunkedFile); + $file['copy_file'] = true; + } + + $globalFile = []; + $globalFile['files'] = $file; + /** @var Dropbox_SentWork $result */ + $result = store_add_dropbox($file, $work); - $json = []; - if (!empty($result)) { - $json['name'] = Display::url( - api_htmlentities($result->title), - api_htmlentities(api_get_path(WEB_CODE_PATH).'dropbox/index.php?'.api_get_cidreq()), - ['target' => '_blank'] - ); + $json = []; + if (!empty($result)) { + $json['name'] = Display::url( + api_htmlentities($result->title), + api_htmlentities(api_get_path(WEB_CODE_PATH).'dropbox/index.php?'.api_get_cidreq()), + ['target' => '_blank'] + ); - $json['url'] = api_get_path(WEB_CODE_PATH).'dropbox/index.php?'.api_get_cidreq(); - $json['size'] = format_file_size($result->filesize); - $json['type'] = api_htmlentities($file['type']); - $json['result'] = Display::return_icon( - 'accept.png', - get_lang('Uploaded') - ); - } else { - $json['result'] = Display::return_icon( - 'exclamation.png', - get_lang('Error') - ); + $json['url'] = api_get_path(WEB_CODE_PATH).'dropbox/index.php?'.api_get_cidreq(); + $json['size'] = format_file_size($result->filesize); + $json['type'] = api_htmlentities($file['type']); + $json['result'] = Display::return_icon( + 'accept.png', + get_lang('Uploaded') + ); + } else { + $json['result'] = Display::return_icon( + 'exclamation.png', + get_lang('Error') + ); + } + $resultList[] = $json; } - $resultList[] = $json; - } - echo json_encode(['files' => $resultList]); + echo json_encode(['files' => $resultList]); + exit; + } } - exit; break; } exit; diff --git a/main/inc/ajax/exercise.ajax.php b/main/inc/ajax/exercise.ajax.php index 15be3f48fb..b4c2399add 100755 --- a/main/inc/ajax/exercise.ajax.php +++ b/main/inc/ajax/exercise.ajax.php @@ -811,6 +811,194 @@ switch ($action) { header('Content-Type: application/json'); echo json_encode($result); break; + case 'browser_test': + $quizCheckButtonEnabled = api_get_configuration_value('quiz_check_button_enable'); + + if ($quizCheckButtonEnabled) { + if (isset($_POST['sleep'])) { + sleep(2); + } + + echo 'ok'; + } + + break; + case 'quiz_confirm_saved_answers': + if (false === api_get_configuration_value('quiz_confirm_saved_answers')) { + break; + } + + $trackConfirmationId = isset($_POST['tc_id']) ? (int) $_POST['tc_id'] : 0; + $cId = api_get_course_int_id(); + $sessionId = api_get_session_id(); + $userId = api_get_user_id(); + $confirmed = !empty($_POST['quiz_confirm_saved_answers_check']); + + $em = Database::getManager(); + $repo = $em->getRepository('ChamiloCoreBundle:TrackEExerciseConfirmation'); + + try { + if (!$trackConfirmationId) { + throw new Exception(get_lang('ErrorOccurred')); + } + + /** @var TrackEExerciseConfirmation $trackConfirmation */ + $trackConfirmation = $repo->findOneBy( + [ + 'id' => $trackConfirmationId, + 'userId' => $userId, + 'courseId' => $cId, + 'sessionId' => $sessionId, + ], + ['createdAt' => 'DESC'] + ); + + if (!$trackConfirmation) { + throw new Exception(get_lang('NotFound')); + } + + $trackConfirmation + ->setConfirmed($confirmed) + ->setUpdatedAt(api_get_utc_datetime(null, false, true)); + + $em->persist($trackConfirmation); + $em->flush(); + + http_response_code(200); + } catch (Exception $exception) { + http_response_code(500); + + echo Display::return_message($exception->getMessage(), 'error'); + } + + break; + case 'sign_attempt': + api_block_anonymous_users(); + if ('true' !== api_get_plugin_setting('exercise_signature', 'tool_enable')) { + exit; + } + + $file = isset($_REQUEST['file']) ? $_REQUEST['file'] : ''; + if (empty($exeId) || empty($file)) { + echo 0; + exit; + } + + $file = str_replace(' ', '+', $file); + $track = ExerciseLib::get_exercise_track_exercise_info($exeId); + if ($track) { + $result = ExerciseSignaturePlugin::saveSignature($currentUserId, $track, $file); + if ($result) { + echo 1; + exit; + } + } + echo 0; + break; + case 'upload_answer': + api_block_anonymous_users(); + + if (isset($_REQUEST['chunkAction']) && 'send' === $_REQUEST['chunkAction']) { + // It uploads the files in chunks + if (!empty($_FILES)) { + $tempDirectory = api_get_path(SYS_ARCHIVE_PATH); + $files = $_FILES['files']; + $fileList = []; + foreach ($files as $name => $array) { + $counter = 0; + foreach ($array as $data) { + $fileList[$counter][$name] = $data; + $counter++; + } + } + if (!empty($fileList)) { + foreach ($fileList as $n => $file) { + $tmpFile = disable_dangerous_file( + api_replace_dangerous_char($file['name']) + ); + + file_put_contents( + $tempDirectory.$tmpFile, + fopen($file['tmp_name'], 'r'), + FILE_APPEND + ); + } + } + } + echo json_encode([ + 'files' => $_FILES, + 'errorStatus' => 0, + ]); + exit; + } else { + if (!empty($_FILES)) { + $currentDirectory = Security::remove_XSS($_REQUEST['curdirpath']); + $userId = api_get_user_id(); + + // Upload answer path is created inside user personal folder my_files/upload_answer/[exe_id]/[question_id] + $syspath = UserManager::getUserPathById($userId, 'system').'my_files'.$currentDirectory; + @mkdir($syspath, api_get_permissions_for_new_directories(), true); + $webpath = UserManager::getUserPathById($userId, 'web').'my_files'.$currentDirectory; + + $files = $_FILES['files']; + $fileList = []; + foreach ($files as $name => $array) { + $counter = 0; + foreach ($array as $data) { + $fileList[$counter][$name] = $data; + $counter++; + } + } + $resultList = []; + foreach ($fileList as $file) { + $json = []; + + if (isset($_REQUEST['chunkAction']) && 'done' === $_REQUEST['chunkAction']) { + // to rename and move the finished file + $chunkedFile = api_get_path(SYS_ARCHIVE_PATH).$file['name']; + $file['tmp_name'] = $chunkedFile; + $file['size'] = filesize($chunkedFile); + $file['copy_file'] = true; + } + + $filename = api_replace_dangerous_char($file['name']); + $filename = disable_dangerous_file($filename); + + if (isset($file['copy_file']) && $file['copy_file']) { + $uploaded = copy($file['tmp_name'], $syspath.$filename); + @unlink($file['tmp_name']); + } else { + $uploaded = move_uploaded_file($file['tmp_name'], $syspath.$filename); + } + + if ($uploaded) { + $title = $filename; + $url = $webpath.$filename; + $json['name'] = api_htmlentities($title); + $json['link'] = Display::url( + api_htmlentities($title), + api_htmlentities($url), + ['target' => '_blank'] + ); + $json['url'] = $url; + $json['size'] = format_file_size($file['size']); + $json['type'] = api_htmlentities($file['type']); + $json['result'] = Display::return_icon( + 'accept.png', + get_lang('Uploaded') + ); + } else { + $json['name'] = isset($file['name']) ? $filename : get_lang('Unknown'); + $json['url'] = ''; + $json['error'] = get_lang('Error'); + } + $resultList[] = $json; + } + echo json_encode(['files' => $resultList]); + exit; + } + } + break; default: echo ''; } diff --git a/main/inc/ajax/work.ajax.php b/main/inc/ajax/work.ajax.php index 77ea6d9864..07ef19bb23 100755 --- a/main/inc/ajax/work.ajax.php +++ b/main/inc/ajax/work.ajax.php @@ -60,10 +60,44 @@ switch ($action) { api_protect_course_script(true); $workId = isset($_REQUEST['id']) ? $_REQUEST['id'] : ''; - $workInfo = get_work_data_by_id($workId); - $sessionId = api_get_session_id(); - $userId = api_get_user_id(); - $groupId = api_get_group_id(); + if (isset($_REQUEST['chunkAction']) && 'send' === $_REQUEST['chunkAction']) { + // It uploads the files in chunks + if (!empty($_FILES)) { + $tempDirectory = api_get_path(SYS_ARCHIVE_PATH); + $files = $_FILES['files']; + $fileList = []; + foreach ($files as $name => $array) { + $counter = 0; + foreach ($array as $data) { + $fileList[$counter][$name] = $data; + $counter++; + } + } + if (!empty($fileList)) { + foreach ($fileList as $n => $file) { + $tmpFile = disable_dangerous_file( + api_replace_dangerous_char($file['name']) + ); + + file_put_contents( + $tempDirectory.$tmpFile, + fopen($file['tmp_name'], 'r'), + FILE_APPEND + ); + } + } + } + echo json_encode([ + 'files' => $_FILES, + 'errorStatus' => 0, + ]); + exit; + } else { + $workId = isset($_REQUEST['id']) ? $_REQUEST['id'] : ''; + $workInfo = get_work_data_by_id($workId); + $sessionId = api_get_session_id(); + $userId = api_get_user_id(); + $groupId = api_get_group_id(); $onlyOnePublication = api_get_configuration_value('allow_only_one_student_publication_per_user'); if ($onlyOnePublication) { diff --git a/main/inc/lib/fileUpload.lib.php b/main/inc/lib/fileUpload.lib.php index d8330be011..bcddecdb27 100755 --- a/main/inc/lib/fileUpload.lib.php +++ b/main/inc/lib/fileUpload.lib.php @@ -12,6 +12,8 @@ * @todo test and reorganise */ +use enshrined\svgSanitize\Sanitizer; + /** * Changes the file name extension from .php to .phps * Useful for securing a site. @@ -28,7 +30,7 @@ function php2phps($file_name) } /** - * Renames .htaccess & .HTACCESS to htaccess.txt. + * Renames .htaccess & .HTACCESS & .htAccess to htaccess.txt. * * @param string $filename * @@ -36,7 +38,7 @@ function php2phps($file_name) */ function htaccess2txt($filename) { - return str_replace(['.htaccess', '.HTACCESS'], ['htaccess.txt', 'htaccess.txt'], $filename); + return str_ireplace('.htaccess', 'htaccess.txt', $filename); } /** @@ -191,6 +193,22 @@ function process_uploaded_file($uploaded_file, $show_output = true) return true; } +function sanitizeSvgFile(string $fullPath) +{ + $fileType = mime_content_type($fullPath); + + if ('image/svg+xml' !== $fileType) { + return; + } + + $svgContent = file_get_contents($fullPath); + + $sanitizer = new Sanitizer(); + $cleanSvg = $sanitizer->sanitize($svgContent); + + file_put_contents($fullPath, $cleanSvg); +} + /** * This function does the save-work for the documents. * It handles the uploaded file and adds the properties to the database @@ -394,6 +412,7 @@ function handle_uploaded_document( $fileExists = file_exists($fullPath); if (moveUploadedFile($uploadedFile, $fullPath)) { + sanitizeSvgFile($fullPath); chmod($fullPath, $filePermissions); if ($fileExists && $docId) { @@ -577,6 +596,7 @@ function handle_uploaded_document( $filePath = $uploadPath.$fileSystemName; if (moveUploadedFile($uploadedFile, $fullPath)) { + sanitizeSvgFile($fullPath); chmod($fullPath, $filePermissions); // Put the document data in the database $documentId = add_document( diff --git a/main/install/configuration.dist.php b/main/install/configuration.dist.php index cd28351fed..8db8984a3c 100755 --- a/main/install/configuration.dist.php +++ b/main/install/configuration.dist.php @@ -1689,3 +1689,235 @@ INSERT INTO `extra_field` (`extra_field_type`, `field_type`, `variable`, `displa */ //$_configuration['allow_course_multiple_languages'] = false; +// Update user expiration in x days or months when login the first time +/*$_configuration['update_student_expiration_x_date'] = [ + 'days' => 0, + 'months' => 0, +];*/ + +// Enables to define which user status to show when option is true from $_configuration['user_status_show_option'] +//$_configuration['user_status_show_options_enabled'] = false; +// The user status is hidden when is false, it requires $_configuration['user_status_show_options_enabled'] = true +/*$_configuration['user_status_show_option'] = [ + 'COURSEMANAGER' => true, + 'STUDENT' => true, + 'DRH' => false, + 'SESSIONADMIN' => false, + 'STUDENT_BOSS' => false, + 'INVITEE' => false +];*/ + +// Allow learnpath prerequisite on quiz to unblock if maximum attempt is reached +//$_configuration['lp_prerequisit_on_quiz_unblock_if_max_attempt_reached'] = false; + +// Enables to hide user status when option is true visible only for admins from $_configuration['user_status_option_show_only_for_admin'] +//$_configuration['user_status_option_only_for_admin_enabled'] = false; +// The user status is hidden when is false, it requires $_configuration['user_status_option_only_for_admin_enabled'] = true +/*$_configuration['user_status_option_show_only_for_admin'] = [ + 'COURSEMANAGER' => false, + 'STUDENT' => false, + 'DRH' => false, + 'SESSIONADMIN' => true, + 'STUDENT_BOSS' => false, + 'INVITEE' => false + +// Set the default expiration date when a user is created by role and days +/*$_configuration['user_number_of_days_for_default_expiration_date_per_role'] = [ + 'COURSEMANAGER' => 365, + 'STUDENT' => 31, + 'DRH' => 31, + 'SESSIONADMIN' => 60, + 'STUDENT_BOSS' => 60, + 'INVITEE' => 31 +];*/ + +// Course extra fields to be presented on main/create_course/add_course.php +//$_configuration['course_creation_by_teacher_extra_fields_to_show'] = ['fields' => ['ExtrafieldLabel1', 'ExtrafieldLabel2']]; + +// Configuration setting to make some extra field required in course creation form. +//$_configuration['course_creation_form_set_extra_fields_mandatory'] = ['fields' => ['fieldLabel1','fieldLabel2']]; + +// Course extra fields to be presented on course settings +//$_configuration['course_configuration_tool_extra_fields_to_show_and_edit'] = ['fields' => ['ExtrafieldLabel1', 'ExtrafieldLabel2']]; + +// Relation to prefill course extra field with user extra field on course creacion on main/create_course/add_course.php and main/admin/course_add.php +/*$_configuration['course_creation_user_course_extra_field_relation_to_prefill'] = [ + 'fields' => [ + 'CourseExtrafieldLabel1' => 'UserExtrafieldLabel1', + 'CourseExtrafieldLabel2' => 'UserExtrafieldLabel2', + ] +];*/ + +// Hides the icon of percentage in "Average of tests in Learning Paths" indication on a student tracking +// $_configuration['student_follow_page_hide_lp_tests_average'] = false; + +// Add navigation to the next or previous lp without going to the list. +// Requires DB change: +// ALTER TABLE c_lp ADD next_lp_id int(11) NOT NULL DEFAULT '0'; +//$_configuration['lp_enable_flow'] = false; + +// User extra fields to be check on user edition to generate a specific process if it was modified +//$_configuration['user_edition_extra_field_to_check'] = 'ExtrafieldLabel'; + +// Enable skills in subcategory to work independant on assignement +// Require DB changes: +// ALTER TABLE gradebook_category ADD allow_skills_by_subcategory tinyint(1) NULL DEFAULT '1'; +// Requires edit Entity GradebookCategory: src/Chamilo/CoreBundle/Entity/GradebookCategory.php uncomment "allowSkillsBySubcategory" variable. +//$_configuration['gradebook_enable_subcategory_skills_independant_assignement'] = false; + +// Shows the deleted quizzes in my progress page. +//$_configuration['tracking_my_progress_show_deleted_exercises'] = true; + +// Hide IP in exercises reports +// $_configuration['exercise_hide_ip'] = false; + +// Enable signature in attendance sheet for users +// Require DB changes: +// ALTER TABLE c_attendance_sheet ADD signature longtext NULL; +// ALTER TABLE c_attendance_calendar ADD blocked tinyint(1) NULL; +// Requires edit Entity CAttendanceSheet : src/Chamilo/CourseBundle/Entity/CAttendanceSheet.php add the @ symbol for attribute $signature into ORM\Column() line. +// Requires edit Entity CAttendanceCalendar : src/Chamilo/CourseBundle/Entity/CAttendanceCalendar.php add the @ symbol for attribute $blocked into ORM\Column() line. +//$_configuration['enable_sign_attendance_sheet'] = false; + +// Make sessions by duration always accessible to coaches (otherwise +// they are only accessible during the active duration). +//$_configuration['session_coach_access_after_duration_end'] = false; + +// Restrict the list of students to subscribe in the course session. And disable +// registration for users in all courses from Resume Session page +//$_configuration['session_course_users_subscription_limited_to_session_users'] = false; + +// Disable tab to add classes in course session for non-admins +//$_configuration['session_classes_tab_disable'] = false; + +// Disable the possibility for teachers to edit course visibility +//$_configuration['course_visibility_change_only_admin'] = false; + +// Allow DRH user to access all students from reporting. +// $_configuration['drh_allow_access_to_all_students'] = false; + +// Disable links in gradebook view for students +// $_configuration['gradebook_hide_link_to_item_for_student'] = false; + +// It adds option to define if a document can be downloaded or not. +// Create a document extra field with field label "can_be_downloaded" of type "Checkbox options". +// $_configuration['documents_hide_download_icon'] = false; + +// Add the username value to the "subscription to session" confirmation email +//$_configuration['email_template_subscription_to_session_confirmation_username'] = false; + +// Add the "remember password" link to the "subscription to session" confirmation email +//$_configuration['email_template_subscription_to_session_confirmation_lost_password'] = false; + +// Add a custom extra footer for notificacions emails for a specific language, for example for +// privacy policy notices. Multiple languages and paragraphs can be added. +/*$_configuration['notifications_extended_footer_message'] = ['english' => ['paragraphs' => [ + 'Change or delete this paragraph or add another one' +]]];*/ + +// Option to define duration for a calendar in attendance sheet. +// Create an attendance calendar extra field with field label "duration" of type "text". +// $_configuration['attendance_calendar_set_duration'] = false; + +// Enable comments in attendance sheet for users +// Require DB changes: +//CREATE TABLE c_attendance_result_comment (iid int not null PRIMARY KEY AUTO_INCREMENT, attendance_sheet_id int not null, user_id int not null, created_at datetime not null, updated_at datetime not null, comment text not null, author_user_id int not null); +//CREATE INDEX c_attendance_sheet_user ON track_e_access_complete (attendance_sheet_id, user_id); +// Then add the "@" symbol to CAttendanceResultComment class in the ORM\Entity() line. +//$_configuration['attendance_allow_comments'] = false; + +// Enable categories in Wiki tool. +// 1. Run the following DB changes: +/* +CREATE TABLE c_wiki_rel_category (wiki_id INT NOT NULL, category_id INT NOT NULL, INDEX IDX_AC88945BAA948DBE (wiki_id), INDEX IDX_AC88945B12469DE2 (category_id), PRIMARY KEY(wiki_id, category_id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB; +CREATE TABLE c_wiki_category (id INT AUTO_INCREMENT NOT NULL, c_id INT NOT NULL, session_id INT DEFAULT NULL, tree_root INT DEFAULT NULL, parent_id INT DEFAULT NULL, name VARCHAR(255) NOT NULL, lft INT NOT NULL, lvl INT NOT NULL, rgt INT NOT NULL, INDEX IDX_17F1099A91D79BD3 (c_id), INDEX IDX_17F1099A613FECDF (session_id), INDEX IDX_17F1099AA977936C (tree_root), INDEX IDX_17F1099A727ACA70 (parent_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE `utf8_unicode_ci` ENGINE = InnoDB; +ALTER TABLE c_wiki_rel_category ADD CONSTRAINT FK_AC88945BAA948DBE FOREIGN KEY (wiki_id) REFERENCES c_wiki (iid) ON DELETE CASCADE; +ALTER TABLE c_wiki_rel_category ADD CONSTRAINT FK_AC88945B12469DE2 FOREIGN KEY (category_id) REFERENCES c_wiki_category (id) ON DELETE CASCADE; +ALTER TABLE c_wiki_category ADD CONSTRAINT FK_17F1099A91D79BD3 FOREIGN KEY (c_id) REFERENCES course (id) ON DELETE CASCADE; +ALTER TABLE c_wiki_category ADD CONSTRAINT FK_17F1099A613FECDF FOREIGN KEY (session_id) REFERENCES session (id) ON DELETE CASCADE; +ALTER TABLE c_wiki_category ADD CONSTRAINT FK_17F1099AA977936C FOREIGN KEY (tree_root) REFERENCES c_wiki_category (id) ON DELETE CASCADE; +ALTER TABLE c_wiki_category ADD CONSTRAINT FK_17F1099A727ACA70 FOREIGN KEY (parent_id) REFERENCES c_wiki_category (id) ON DELETE CASCADE; +*/ +// 2. Add an "@" before "ORM\ManyToMany" and "@ORM\JoinTable" in the "CWiki::$categories" property definition (in src/Chamilo/CourseBundle/Entity/CWiki.php) +// 3. Add an "@" before "ORM\Entity" in the "CWikiCategory" class definition (in src/Chamilo/CourseBundle/Entity/CWikiCategory.php) +//$_configuration['wiki_categories_enabled'] = false; + +// Relation to prefill session extra field with user extra field on session creation on main/session/session_add.php +/*$_configuration['session_creation_user_course_extra_field_relation_to_prefill'] = [ + 'fields' => [ + 'client' => 'client', + 'region' => 'region', + ] +];*/ + +// It adds option to define prerequisites with start and end dates for learnpath items. +// Requires DB changes: +/* +INSERT INTO extra_field (extra_field_type, field_type, variable, display_text, default_value, field_order, visible_to_self, visible_to_others, changeable, filter, created_at) VALUES +(7, 7, 'start_date', 'StartDate', '', 0, 1, 0, 1, 0, NOW()); +INSERT INTO extra_field (extra_field_type, field_type, variable, display_text, default_value, field_order, visible_to_self, visible_to_others, changeable, filter, created_at) VALUES +(7, 7, 'end_date', 'EndDate', '', 0, 1, 0, 1, 0, NOW()); +*/ +//$_configuration['lp_item_prerequisite_dates'] = false; + +// Configuration setting to make some extra field required in session creation form on main/session/session_add.php. +// $_configuration['session_creation_form_set_extra_fields_mandatory'] = ['fields' => ['client','region']]; + +// Ask REST webservices (v2.php) to return another identifier for fields related to user ID. +// This is useful if the external system doesn't really deal with user IDs as they are in Chamilo, as it helps +// the external system match the user data return with some external data that is know to Chamilo. For example, if +// you use an external authentication system, you can return the extra field used to match the user with the +// external authentication system rather than user.id. +// $_configuration['webservice_return_user_field'] = 'oauth2_id'; + +// Add support for careers hierarchy - refs BT#20711 +// 1. This requires the following DB change: +// ALTER TABLE career add parent_id INT +// ALTER TABLE career add constraint career_career_id_fk foreign key (parent_id) references career (id); +// 2. Add an "@" before "var int" and "ORM\Column..." in the "Career::$parentId" property definition (in src/Chamilo/CoreBundle/Entity/Career.php) +// 3. Uncomment $parentId var in src/Chamilo/CoreBundle/Entity/Career.php +// $_configuration['career_hierarchy_enable'] = false; + +// KEEP THIS AT THE END +// -------- Custom DB changes +// Set to true to hide settings completely in a sub-URL if the setting is disabled in the +// main URL (where the access_url_changeable field = 0) +// $_configuration['multiple_url_hide_disabled_settings'] = false; + +// List of learner certificates - User extra fields to include at the exported CSV as columns +//$_configuration['certificate_export_report_user_extra_fields'] = ['extra_fields' => ['office_address', 'office_phone_extension']]; + +// Only courses with this option will be visible in catalogue +// Requires DB changes: +/* +INSERT INTO extra_field (extra_field_type, field_type, variable, display_text, default_value, field_order, visible_to_self, visible_to_others, changeable, filter, created_at) VALUES +(2, 3, 'show_in_catalogue', 'Show in catalogue', '', 0, 1, 1, 1, 0, NOW()); +SET @ef_id = LAST_INSERT_ID(); +INSERT INTO extra_field_options (field_id, option_value, display_text, priority, priority_message, option_order) VALUES +(@ef_id, '1', 'Yes', NULL, NULL, 1), +(@ef_id, '0', 'No', NULL, NULL, 2); +*/ +//$_configuration['show_courses_in_catalogue'] = false; + +// Allows defining one or several categories of courses that will be visible in the course catalog +// $_configuration['courses_catalogue_show_only_category'] = ['Cat1','Cat2']; + +//Hides the link to the course catalog in the menu when the catalog is public. +// $_configuration['catalog_hide_public_link'] = false; + +// Display the Portal News link in the admin page to session admin users +//$_configuration['session_admin_access_system_announcement'] = false; + +// File upload size limit in MB for teachers (set to 1024 for 1GB, 5120 for 5GB, etc). +//$_configuration['file_upload_size_limit_for_teacher'] = 0; + +// Add user activation by confirmation email +// This option prevents the new user to login in the platform if your account is not confirmed via email +// You need add a new option called "confirmation" to the registration settings +//INSERT INTO settings_options (variable, value, display_text) VALUES ('allow_registration', 'confirmation', 'MailConfirmation'); + +// Enable use of a custom course logo in mail & PDF headers +// $_configuration['mail_header_from_custom_course_logo'] = false; + +// Enable additional_webservices.php for *remote* PPT2PNG/Oogie service +//$_configuration['webservice_remote_ppt2png_enable'] = false; diff --git a/main/lp/openoffice_document.class.php b/main/lp/openoffice_document.class.php index deedff45a4..08f252dc8c 100755 --- a/main/lp/openoffice_document.class.php +++ b/main/lp/openoffice_document.class.php @@ -95,8 +95,8 @@ abstract class OpenofficeDocument extends learnpath if (!empty($size)) { list($w, $h) = explode('x', $size); if (!empty($w) && !empty($h)) { - $this->slide_width = $w; - $this->slide_height = $h; + $this->slide_width = (int) $w; + $this->slide_height = (int) $h; } } @@ -132,6 +132,7 @@ abstract class OpenofficeDocument extends learnpath $files = []; $return = 0; + $cmd = escapeshellcmd($cmd); $shell = exec($cmd, $files, $return); if ($return != 0) { // If the java application returns an error code. @@ -237,7 +238,9 @@ abstract class OpenofficeDocument extends learnpath $cmd .= ' -p '.api_get_setting('service_ppt2lp', 'port'); // Call to the function implemented by child. - $cmd .= ' "'.$this->base_work_dir.'/'.$this->file_path.'" "'.$this->base_work_dir.'/'.$this->created_dir.'"'; + $cmd .= ' "'.Security::sanitizeExecParam($this->base_work_dir.'/'.$this->file_path) + .'" "' + .Security::sanitizeExecParam($this->base_work_dir.'/'.$this->created_dir).'"'; // To allow openoffice to manipulate docs. @chmod($this->base_work_dir, $permissionFolder); @chmod($this->base_work_dir.'/'.$this->file_path, $permissionFile); @@ -247,6 +250,7 @@ abstract class OpenofficeDocument extends learnpath $files = []; $return = 0; + $cmd = escapeshellcmd($cmd); $shell = exec($cmd, $files, $return); // TODO: Chown is not working, root keep user privileges, should be www-data @chown($this->base_work_dir.'/'.$this->created_dir, 'www-data'); diff --git a/main/lp/openoffice_presentation.class.php b/main/lp/openoffice_presentation.class.php index d633f46672..4279ed8b3b 100755 --- a/main/lp/openoffice_presentation.class.php +++ b/main/lp/openoffice_presentation.class.php @@ -241,16 +241,22 @@ class OpenofficePresentation extends OpenofficeDocument public function add_command_parameters() { if (empty($this->slide_width) || empty($this->slide_height)) { - list($this->slide_width, $this->slide_height) = explode('x', api_get_setting('service_ppt2lp', 'size')); + list($w, $h) = explode('x', api_get_setting('service_ppt2lp', 'size')); + + $this->slide_width = (int) $w; + $this->slide_height = (int) $h; } - return ' -w '.$this->slide_width.' -h '.$this->slide_height.' -d oogie "'.$this->base_work_dir.'/'.$this->file_path.'" "'.$this->base_work_dir.$this->created_dir.'.html"'; + return ' -w '.$this->slide_width.' -h '.$this->slide_height.' -d oogie ' + .Security::sanitizeExecParam($this->base_work_dir.'/'.$this->file_path) + .' ' + .Security::sanitizeExecParam($this->base_work_dir.$this->created_dir.'.html'); } public function set_slide_size($width, $height) { - $this->slide_width = $width; - $this->slide_height = $height; + $this->slide_width = (int) $width; + $this->slide_height = (int) $height; } public function add_docs_to_visio($files = []) diff --git a/main/lp/openoffice_text.class.php b/main/lp/openoffice_text.class.php index 72ccde781a..864b936675 100755 --- a/main/lp/openoffice_text.class.php +++ b/main/lp/openoffice_text.class.php @@ -331,7 +331,10 @@ class OpenofficeText extends OpenofficeDocument */ public function add_command_parameters() { - return ' -d woogie "'.$this->base_work_dir.'/'.$this->file_path.'" "'.$this->base_work_dir.$this->created_dir.'/'.$this->file_name.'.html"'; + return ' -d woogie ' + .Security::sanitizeExecParam($this->base_work_dir.'/'.$this->file_path) + .' ' + .Security::sanitizeExecParam($this->base_work_dir.$this->created_dir.'/'.$this->file_name.'.html'); } /** diff --git a/main/lp/openoffice_text_document.class.php b/main/lp/openoffice_text_document.class.php index 96e9b58c2f..a17de75e51 100755 --- a/main/lp/openoffice_text_document.class.php +++ b/main/lp/openoffice_text_document.class.php @@ -333,7 +333,10 @@ class OpenOfficeTextDocument extends OpenofficeDocument */ public function add_command_parameters() { - return ' -d woogie "'.$this->base_work_dir.'/'.$this->file_path.'" "'.$this->base_work_dir.$this->created_dir.'/'.$this->file_name.'.html"'; + return ' -d woogie ' + .Security::sanitizeExecParam($this->base_work_dir.'/'.$this->file_path) + .' ' + .Security::sanitizeExecParam($this->base_work_dir.$this->created_dir.'/'.$this->file_name.'.html'); } /** diff --git a/main/session/session_import.php b/main/session/session_import.php index f27dd633e6..d076fb3046 100644 --- a/main/session/session_import.php +++ b/main/session/session_import.php @@ -168,9 +168,14 @@ if (isset($_POST['formSent']) && $_POST['formSent']) { // Looking up for the teacher. $username = trim(api_utf8_decode($courseNode->CourseTeacher)); - $sql = "SELECT user_id, lastname, firstname FROM $tbl_user WHERE username='$username'"; - $rs = Database::query($sql); - list($user_id, $lastname, $firstname) = Database::fetch_array($rs); + $rs = Database::select( + ['user_id', 'lastname', 'firstname'], + $tbl_user, + ['where' => ['username = ?' => $username]], + 'first', + 'NUM' + ); + list($user_id, $lastname, $firstname) = $rs; $params['teachers'] = $user_id; CourseManager::create_course($params); diff --git a/main/webservices/additional_webservices.php b/main/webservices/additional_webservices.php index 329f787156..44ff50b778 100755 --- a/main/webservices/additional_webservices.php +++ b/main/webservices/additional_webservices.php @@ -7,6 +7,14 @@ */ require_once __DIR__.'/../inc/global.inc.php'; +$enableThis = api_get_configuration_value('webservice_remote_ppt2png_enable'); +if (!$enableThis) { + echo "Remote PPT2PNG service is disabled. \n"; + echo "To enable, add \$_configuration['webservice_remote_ppt2png_enable'] = true; to your configuration.php"; + exit; +} +api_protect_webservices(); + /** * Function to convert from ppt to png * This function is used from Chamilo Rapid Lesson. @@ -28,18 +36,26 @@ function wsConvertPpt($pptData) } $fileData = $pptData['file_data']; // Clean filename to avoid hacks. Prevents "&" and ";" to be used in filename, notably - $sanitizedFileName = Security::sanitizeExecParam($pptData['file_name']); + + if (strpos($pptData['file_name'], '..') !== false) { + return false; + } + + $sanitizedFileName = $pptData['file_name']; $dataInfo = pathinfo($sanitizedFileName); $fileName = basename($sanitizedFileName, '.'.$dataInfo['extension']); // Add additional cleaning of .php and .htaccess files $fullFileName = Security::filter_filename($sanitizedFileName); - $size = Security::sanitizeExecParam($pptData['service_ppt2lp_size']); + $size = $pptData['service_ppt2lp_size']; $w = '800'; $h = '600'; if (!empty($size)) { list($w, $h) = explode('x', $size); } + $w = (int) $w; + $h = (int) $h; + $tempArchivePath = api_get_path(SYS_ARCHIVE_PATH); $tempPath = $tempArchivePath.'wsConvert/'.$fileName.'/'; $tempPathNewFiles = $tempArchivePath.'wsConvert/'.$fileName.'-n/'; @@ -54,8 +70,12 @@ function wsConvertPpt($pptData) $file = base64_decode($fileData); file_put_contents($tempPath.$fullFileName, $file); - $cmd = pptConverterGetCommandBaseParams(); - $cmd .= ' -w '.$w.' -h '.$h.' -d oogie "'.$tempPath.$fullFileName.'" "'.$tempPathNewFiles.$fileName.'.html"'; + $cmd = pptConverterGetCommandBaseParams( + $w, + $h, + $tempPath.$fullFileName, + $tempPathNewFiles.$fileName.'.html' + ); //$perms = api_get_permissions_for_new_files(); chmod($tempPathNewFiles.$fileName, $perms); @@ -135,21 +155,27 @@ function pptConverterDirectoriesCreate($tempPath, $tempPathNewFiles, $fileName, * * @return string $cmd */ -function pptConverterGetCommandBaseParams() +function pptConverterGetCommandBaseParams(int $w, int $h, string $inputPath, string $outputPath) { + $cd = ''; + if (IS_WINDOWS_OS) { // IS_WINDOWS_OS has been defined in main_api.lib.php $converterPath = str_replace('/', '\\', api_get_path(SYS_PATH).'main/inc/lib/ppt2png'); $classPath = $converterPath.';'.$converterPath.'/jodconverter-2.2.2.jar;'.$converterPath.'/jodconverter-cli-2.2.2.jar'; - $cmd = 'java -Dfile.encoding=UTF-8 -cp "'.$classPath.'" DokeosConverter'; + $cmd = 'java -Dfile.encoding=UTF-8 -cp "'.$classPath.'"'; } else { $converterPath = api_get_path(SYS_PATH).'main/inc/lib/ppt2png'; $classPath = ' -Dfile.encoding=UTF-8 -cp .:jodconverter-2.2.2.jar:jodconverter-cli-2.2.2.jar'; - $cmd = 'cd '.$converterPath.' && java '.$classPath.' DokeosConverter'; + $cd = 'cd '.$converterPath.' && '; + $cmd = 'java '.$classPath; } + $cmd .= ' DokeosConverter'; $cmd .= ' -p '.api_get_setting('service_ppt2lp', 'port'); + $cmd .= ' -w '.$w.' -h '.$h; + $cmd .= ' -d oogie '.Security::sanitizeExecParam($inputPath).' '.Security::sanitizeExecParam($outputPath); - return $cmd; + return $cd.escapeshellcmd($cmd); } $webPath = api_get_path(WEB_PATH);