=== Rediafile Developer Portal — VPS / Apache deployment package === Preset: Apache 2.4 + PHP 8.2 — Production VPS ---------------------------------------------------------------------- ## 1. Apache VirtualHost (sites-available/rediafile.conf) ServerName portal.example.com DocumentRoot /var/www/rediafile-php/public DirectoryIndex index.php AllowOverride All Require all granted Options -Indexes +FollowSymLinks # Deny access to application files outside /public Require all denied ErrorLog ${APACHE_LOG_DIR}/rediafile-portal_error.log CustomLog ${APACHE_LOG_DIR}/rediafile-portal_access.log combined ## 2. .htaccess (place in the web root) RewriteEngine On RewriteCond %{REQUEST_URI} ^/assets/ [NC] RewriteRule ^ - [L] RewriteCond %{REQUEST_FILENAME} -f [OR] RewriteCond %{REQUEST_FILENAME} -d RewriteRule ^ - [L] RewriteRule ^ index.php [QSA,L] Header set Access-Control-Allow-Origin "*" Header set Access-Control-Allow-Methods "GET, POST, OPTIONS" Header set Access-Control-Allow-Headers "Content-Type, Authorization" php_value upload_max_filesize 10240M php_value post_max_size 10240M php_value max_execution_time 3600 php_value max_input_time 3600 php_value memory_limit 512M ## 3. php.ini directives (or conf.d/rediafile.ini) ; Rediafile Developer Portal — php.ini tuning for 10GB uploads upload_max_filesize = 10240M post_max_size = 10240M max_execution_time = 3600 max_input_time = 3600 memory_limit = 512M max_file_uploads = 100 ; Production error handling display_errors = Off error_reporting = E_ALL & ~E_DEPRECATED & ~E_NOTICE log_errors = On ; Session security session.cookie_httponly = 1 session.cookie_samesite = "Lax" session.use_strict_mode = 1 ; OPcache (recommended) opcache.enable = 1 opcache.memory_consumption = 128 opcache.max_accelerated_files = 10000 ## 4. PHP SDK — RediafileClient class (src/RediafileClient.php) tokenFile = \$tokenCacheFile ?? sys_get_temp_dir() . '/rediafile_token.json'; } /** Authenticate and cache the token. */ public function authorize(): string { $cached = $this->loadCachedToken(); if ($cached !== null) { $this->token = $cached; return $cached; } $resp = $this->sendRequest('/authorize', 'POST', [ 'username' => $this->username, 'password' => $this->password, ], false); $data = json_decode($resp, true); $this->token = $data['data']['access_token'] ?? ''; $this->saveCachedToken($this->token, $data['data']['expires_in'] ?? 86400); return $this->token; } /** Upload a local file via multipart/form-data. */ public function uploadFile(string $filePath, ?string $folderId = null): array { $this->ensureToken(); $params = ['file' => new CURLFile($filePath)]; if ($folderId) { $params['folder_id'] = $folderId; } $resp = $this->sendRequest('/file/upload', 'POST', $params); return json_decode($resp, true) ?? []; } /** Get a signed download URL for a short URL. */ public function getDownloadUrl(string $shortUrl): array { $this->ensureToken(); $resp = $this->sendRequest('/file/download', 'GET', ['short_url' => $shortUrl]); return json_decode($resp, true) ?? []; } /** Queue a remote URL for server-to-server upload. */ public function uploadFromRemoteUrl(string $url): array { $this->ensureToken(); $resp = $this->sendRequest('/file/url_upload_add', 'POST', ['url' => $url]); return json_decode($resp, true) ?? []; } /** List contents of a folder. */ public function listFolder(string $folderId = 'fld_root'): array { $this->ensureToken(); $resp = $this->sendRequest('/folder/listing', 'GET', ['folder_id' => $folderId]); return json_decode($resp, true) ?? []; } /** Create a new folder. */ public function createFolder(string $name, ?string $parentId = null, ?string $password = null): array { $this->ensureToken(); $params = ['folder_name' => $name]; if ($parentId) $params['parent_id'] = $parentId; if ($password) $params['password'] = $password; $resp = $this->sendRequest('/folder/create', 'POST', $params); return json_decode($resp, true) ?? []; } /* --- internals --- */ private function ensureToken(): void { if ($this->token === null) { $this->authorize(); } } private function sendRequest(string $path, string $method, array $params = [], bool $withAuth = true): string { $url = $this->baseUrl . $path; $isGet = strtoupper($method) === 'GET'; $fields = $isGet ? http_build_query($params) : $params; if ($isGet && $fields) { $url .= '?' . $fields; } $ch = curl_init($url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method)); $headers = ['Accept: application/json']; if ($withAuth && $this->token) { $headers[] = 'Authorization: Bearer ' . $this->token; } if (!$isGet && $fields) { // If $fields contains a CURLFile, cURL auto-sets multipart $hasFile = false; foreach ($fields as $v) { if ($v instanceof CURLFile) { $hasFile = true; break; } } if (!$hasFile) { $headers[] = 'Content-Type: application/x-www-form-urlencoded'; curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($fields)); } else { curl_setopt($ch, CURLOPT_POSTFIELDS, $fields); } } curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); $resp = curl_exec($ch); curl_close($ch); return is_string($resp) ? $resp : ''; } private function loadCachedToken(): ?string { if (!is_file($this->tokenFile)) return null; $data = json_decode((string) file_get_contents($this->tokenFile), true); if (!is_array($data)) return null; if (($data['expires_at'] ?? 0) < time()) return null; return $data['token'] ?? null; } private function saveCachedToken(string \$token, int $expiresIn): void { file_put_contents($this->tokenFile, json_encode([ 'token' => \$token, 'expires_at' => time() + $expiresIn - 60, ])); } } // --- Usage --- // $client = new RediafileClient('admin', 'secret123'); // $result = $client->uploadFile('/path/to/large-file.zip'); // print_r($result);