diff --git a/common/framework/drivers/sms/ncloud_sens.php b/common/framework/drivers/sms/ncloud_sens.php new file mode 100644 index 000000000..29e2d16e3 --- /dev/null +++ b/common/framework/drivers/sms/ncloud_sens.php @@ -0,0 +1,244 @@ + 100, + 'sms_max_length' => 90, + 'sms_max_length_in_charset' => 'CP949', + 'lms_supported' => true, + 'lms_supported_country_codes' => array(82), + 'lms_max_length' => 2000, + 'lms_max_length_in_charset' => 'CP949', + 'lms_subject_supported' => true, + 'lms_subject_max_length' => 40, + 'mms_supported' => true, + 'mms_supported_country_codes' => array(82), + 'mms_max_length' => 2000, + 'mms_max_length_in_charset' => 'CP949', + 'mms_subject_supported' => true, + 'mms_subject_max_length' => 40, + 'image_allowed_types' => array('jpg'), + 'image_max_dimensions' => array(1500, 1440), + 'image_max_filesize' => 300000, + 'delay_supported' => true, + ); + + /** + * Config keys used by this driver are stored here. + */ + protected static $_required_config = array('service_id', 'api_key', 'api_secret'); + protected static $_optional_config = array(); + + /** + * Get the human-readable name of this SMS driver. + * + * @return string + */ + public static function getName() + { + return 'NAVER Cloud SENS'; + } + + /** + * Check if the current SMS driver is supported on this server. + * + * This method returns true on success and false on failure. + * + * @return bool + */ + public static function isSupported() + { + return true; + } + + /** + * Create a signature for NAVER Cloud gateway server. + * + * @param string $method + * @param string $uri + * @param string $timestamp + * @param string $access_key + * @param string $secret_key + * @return string + */ + protected static function _makeSignature($method, $uri, $timestamp, $access_key, $secret_key): string + { + $content = "$method $uri\n$timestamp\n$access_key"; + return base64_encode(hash_hmac('sha256', $content, $secret_key, true)); + } + + /** + * Upload an attachment and get the file ID. + * + * @param string $filename + * @param string $path + * @return ?string + */ + protected function _uploadFile(string $filename, string $path): ?string + { + // Return null if the file cannot be read. + if (!Storage::exists($path) || !Storage::isReadable($path) || !Storage::isFile($path)) + { + return null; + } + + // Generate the NAVER cloud gateway signature. + $timestamp = floor(microtime(true) * 1000); + $uri = sprintf(self::API_PATH, $this->_config['service_id'], 'files'); + $signature = self::_makeSignature('POST', $uri, $timestamp, $this->_config['api_key'], $this->_config['api_secret']); + $headers = array( + 'x-ncp-apigw-timestamp' => $timestamp, + 'x-ncp-iam-access-key' => $this->_config['api_key'], + 'x-ncp-apigw-signature-v2' => $signature, + ); + + // Send the API request. + try + { + $url = self::API_HOST . sprintf(self::API_PATH, $this->_config['service_id'], 'files'); + $request = \Rhymix\Framework\HTTP::post($url, [], $headers, [], [ + 'timeout' => self::TIMEOUT, + 'json' => [ + 'fileName' => $filename, + 'fileBody' => base64_encode(file_get_contents($path)), + ], + ]); + $result = @json_decode($request->getBody()->getContents()); + if (!empty($result->fileId)) + { + return $result->fileId; + } + else + { + return null; + } + } + catch (\Exception $e) + { + return null; + } + } + + /** + * Send a message. + * + * This method returns true on success and false on failure. + * + * @param array $messages + * @param object $original + * @return bool + */ + public function send(array $messages, \Rhymix\Framework\SMS $original) + { + $status = true; + $file_ids = []; + + foreach ($messages as $i => $message) + { + // Basic information + $data = array(); + $data['type'] = $message->type; + $data['from'] = str_replace('-', '', \Rhymix\Framework\Korea::formatPhoneNumber($message->from)); + if ($message->country && $message->country != 82) + { + $data['countryCode'] = $message->country; + } + + // Subject and content + if ($message->type !== 'SMS' && $message->subject) + { + $data['subject'] = $message->subject; + } + $data['content'] = $message->content; + + // Recipients + foreach ($message->to as $num) + { + $data['messages'][] = [ + 'to' => str_replace('-', '', \Rhymix\Framework\Korea::formatPhoneNumber($num)), + ]; + } + + // Image attachment + if (!empty($message->image)) + { + $path = realpath($message->image); + if (!isset($file_ids[$path])) + { + $file_ids[$path] = $this->_uploadFile('image.jpg', $path); + } + if (isset($file_ids[$path])) + { + $data['files'][] = ['fileId' => $file_ids[$path]]; + } + } + + // Set delay + if ($message->delay && $message->delay > time() + 900) + { + $data['reserveTime'] = gmdate('Y-m-d H:i', $message->delay + (3600 * 9)); + } + + // Generate the NAVER cloud gateway signature. + $timestamp = floor(microtime(true) * 1000); + $uri = sprintf(self::API_PATH, $this->_config['service_id'], 'messages'); + $signature = self::_makeSignature('POST', $uri, $timestamp, $this->_config['api_key'], $this->_config['api_secret']); + $headers = array( + 'x-ncp-apigw-timestamp' => $timestamp, + 'x-ncp-iam-access-key' => $this->_config['api_key'], + 'x-ncp-apigw-signature-v2' => $signature, + ); + + // Send the API request. + try + { + $url = self::API_HOST . sprintf(self::API_PATH, $this->_config['service_id'], 'messages'); + $request = \Rhymix\Framework\HTTP::post($url, [], $headers, [], [ + 'timeout' => self::TIMEOUT, + 'json' => $data, + ]); + $status_code = $request->getStatusCode(); + $response = $request->getBody()->getContents(); + $result = $response ? @json_decode($response) : null; + if (isset($result->statusName)) + { + if ($result->statusName != 'success') + { + $original->addError(trim('NAVER Cloud SENS: ' . $result->statusCode . ' ' . $result->statusName)); + $status = false; + } + } + else + { + $original->addError(trim('NAVER Cloud SENS: ' . $status_code . ' ' . ($result->errorMessage ?? $response))); + $status = false; + } + } + catch (\Exception $e) + { + $original->addError('NAVER Cloud SENS: ' . $e->getMessage()); + $status = false; + } + } + + return $status; + } +}