Open Journal Systems  3.3.0
PKPUploadPublicFileHandler.inc.php
1 <?php
14 import('lib.pkp.classes.handler.APIHandler');
15 
20  public function __construct() {
21  $this->_handlerPath = '_uploadPublicFile';
22  $roles = [ROLE_ID_SITE_ADMIN, ROLE_ID_MANAGER, ROLE_ID_SUB_EDITOR, ROLE_ID_REVIEWER, ROLE_ID_AUTHOR, ROLE_ID_ASSISTANT, ROLE_ID_READER];
23  $this->_endpoints = array(
24  'OPTIONS' => array(
25  array(
26  'pattern' => $this->getEndpointPattern(),
27  'handler' => array($this, 'getOptions'),
28  'roles' => $roles,
29  ),
30  ),
31  'POST' => array(
32  array(
33  'pattern' => $this->getEndpointPattern(),
34  'handler' => array($this, 'uploadFile'),
35  'roles' => $roles,
36  ),
37  ),
38  );
39 
40  parent::__construct();
41  }
42 
46  public function authorize($request, &$args, $roleAssignments) {
47  import('lib.pkp.classes.security.authorization.PolicySet');
48  $rolePolicy = new PolicySet(COMBINING_PERMIT_OVERRIDES);
49 
50  import('lib.pkp.classes.security.authorization.RoleBasedHandlerOperationPolicy');
51  foreach($roleAssignments as $role => $operations) {
52  $rolePolicy->addPolicy(new RoleBasedHandlerOperationPolicy($request, $role, $operations));
53  }
54  $this->addPolicy($rolePolicy);
55 
56  return parent::authorize($request, $args, $roleAssignments);
57  }
58 
66  private function getResponse($response) {
67  return $response->withHeader('Access-Control-Allow-Headers', 'Content-Type, X-Requested-With, X-PINGOTHER, X-File-Name, Cache-Control');
68  }
69 
78  public function uploadFile($slimRequest, $response, $args) {
79  $request = $this->getRequest();
80 
81  if (empty($_FILES) || empty($_FILES['file'])) {
82  return $response->withStatus(400)->withJsonError('api.temporaryFiles.400.noUpload');
83  }
84 
85  $siteDir = Core::getBaseDir() . '/' . Config::getVar('files', 'public_files_dir') . '/site';
86 
87  if (!file_exists($siteDir) || !is_writeable($siteDir)) {
88  return $response->withStatus(500)->withJsonError('api.publicFiles.500.badFilesDir');
89  }
90  $userDir = $siteDir . '/images/' . $request->getUser()->getUsername();
91  $isUserAllowed = true;
92  $allowedDirSize = Config::getVar('files', 'public_user_dir_size', 5000) * 1024;
93  $allowedFileTypes = ['gif', 'jpg', 'png'];
94 
95  HookRegistry::call('API::uploadPublicFile::permissions', [
96  &$userDir,
97  &$isUserAllowed,
98  &$allowedDirSize,
99  &$allowedFileTypes,
100  $request,
101  $this->getAuthorizedContextObject(ASSOC_TYPE_USER_ROLES),
102  ]);
103 
104  // Allow plugins to control who can upload files
105  if (!$isUserAllowed) {
106  return $response->withStatus(403)->withJsonError('api.publicFiles.403.unauthorized');
107  }
108 
109  // Don't allow user to exceed the alotted space in their public directory
110  $currentSize = 0;
111  if ($allowedDirSize > 0 && file_exists($userDir)) {
112  foreach (new RecursiveIteratorIterator(new RecursiveDirectoryIterator($userDir, FilesystemIterator::SKIP_DOTS)) as $object) {
113  $currentSize += $object->getSize();
114  }
115  }
116  if (($currentSize + $_FILES['file']['size']) > $allowedDirSize) {
117  return $response->withStatus(413)->withJsonError('api.publicFiles.413.noDirSpace', [
118  'fileUploadSize' => ceil($_FILES['file']['size']/1024),
119  'dirSizeLeft' => ceil(($allowedDirSize - $currentSize)/1024),
120  ]);
121  }
122 
123  import('lib.pkp.classes.file.FileManager');
124  $fileManager = new FileManager();
125  $filename = $fileManager->getUploadedFileName('file');
126  $filename = trim(
127  preg_replace(
128  "/[^a-z0-9\.\-]+/",
129  "",
130  str_replace(
131  [' ', '_', ':'],
132  '-',
133  strtolower($filename)
134  )
135  )
136  );
137  $extension = pathinfo(strtolower(trim($filename)), PATHINFO_EXTENSION);
138 
139  // Only allow permitted file types
140  if (!in_array($extension, $allowedFileTypes)) {
141  return $response->withStatus(400)->withJsonError('api.publicFiles.400.extensionNotSupported', [
142  'fileTypes' => join(__('common.commaListSeparator'), $allowedFileTypes)
143  ]);
144  }
145 
146  // Perform additional checks on images
147  if (in_array($extension, ['gif', 'jpg', 'jpeg', 'png', 'jpe'])) {
148  if (getimagesize($_FILES['file']['tmp_name']) === false) {
149  return $response->withStatus(400)->withJsonError('api.publicFiles.400.invalidImage');
150  }
151  $extensionFromMimeType = $fileManager->getImageExtension(PKPString::mime_content_type($_FILES['file']['tmp_name']));
152  if ($extensionFromMimeType !== '.' . $extension) {
153  return $response->withStatus(400)->withJsonError('api.publicFiles.400.mimeTypeNotMatched');
154  }
155  }
156 
157  // Save the file
158  $destinationPath = $siteDir . '/images/' . $request->getUser()->getUsername() . '/' . $filename;
159  $success = $fileManager->uploadFile('file', $destinationPath);
160 
161  if ($success === false) {
162  if ($fileManager->uploadError($filename)) {
163  switch ($fileManager->getUploadErrorCode($filename)) {
164  case UPLOAD_ERR_INI_SIZE:
165  case UPLOAD_ERR_FORM_SIZE:
166  return $response->withStatus(400)->withJsonError('api.temporaryFiles.400.fileSize', ['maxSize' => Application::getReadableMaxFileSize()]);
167  case UPLOAD_ERR_PARTIAL:
168  return $response->withStatus(400)->withJsonError('api.temporaryFiles.409.uploadFailed');
169  case UPLOAD_ERR_NO_FILE:
170  return $response->withStatus(400)->withJsonError('api.temporaryFiles.400.noUpload');
171  case UPLOAD_ERR_NO_TMP_DIR:
172  case UPLOAD_ERR_CANT_WRITE:
173  case UPLOAD_ERR_EXTENSION:
174  return $response->withStatus(400)->withJsonError('api.temporaryFiles.400.config');
175  }
176  }
177  return $response->withStatus(400)->withJsonError('api.temporaryFiles.409.uploadFailed');
178  }
179 
180  return $this->getResponse($response->withJson([
181  'url' => $request->getBaseUrl() . '/' .
182  Config::getVar('files', 'public_files_dir') . '/site/images/' .
183  $request->getUser()->getUsername() . '/' .
184  $filename,
185  ]));
186  }
187 
197  public function getOptions($slimRequest, $response, $args) {
198  return $this->getResponse($response);
199  }
200 }
PKPUploadPublicFileHandler
Handle API requests to upload a file to a user's public directory.
Definition: PKPUploadPublicFileHandler.inc.php:16
PKPUploadPublicFileHandler\getOptions
getOptions($slimRequest, $response, $args)
Definition: PKPUploadPublicFileHandler.inc.php:197
Config\getVar
static getVar($section, $key, $default=null)
Definition: Config.inc.php:35
APIHandler
Base request API handler.
Definition: APIHandler.inc.php:22
PKPString\mime_content_type
static mime_content_type($filename, $suggestedExtension='')
Definition: PKPString.inc.php:312
PKPUploadPublicFileHandler\authorize
authorize($request, &$args, $roleAssignments)
Definition: PKPUploadPublicFileHandler.inc.php:46
PKPHandler\getAuthorizedContextObject
& getAuthorizedContextObject($assocType)
Definition: PKPHandler.inc.php:174
PKPApplication\getReadableMaxFileSize
static getReadableMaxFileSize()
Definition: PKPApplication.inc.php:804
Core\getBaseDir
static getBaseDir()
Definition: Core.inc.php:37
RoleBasedHandlerOperationPolicy
Class to control access to handler operations via role based access control.
Definition: RoleBasedHandlerOperationPolicy.inc.php:18
APIHandler\getRequest
getRequest()
Definition: APIHandler.inc.php:149
PKPHandler\addPolicy
addPolicy($authorizationPolicy, $addToTop=false)
Definition: PKPHandler.inc.php:157
FileManager
Class defining basic operations for file management.
Definition: FileManager.inc.php:35
APIHandler\getEndpointPattern
getEndpointPattern()
Definition: APIHandler.inc.php:186
HookRegistry\call
static call($hookName, $args=null)
Definition: HookRegistry.inc.php:86
PKPUploadPublicFileHandler\uploadFile
uploadFile($slimRequest, $response, $args)
Definition: PKPUploadPublicFileHandler.inc.php:78
PolicySet
An ordered list of policies. Policy sets can be added to decision managers like policies....
Definition: PolicySet.inc.php:26
PKPUploadPublicFileHandler\__construct
__construct()
Definition: PKPUploadPublicFileHandler.inc.php:20