Công cụ thành viên

Công cụ trang web


programming4:api

Khác biệt

Đây là những khác biệt giữa hai phiên bản của trang.

Liên kết đến bản xem so sánh này

Phiên bản trước của cả hai bênPhiên bản trước
Phiên bản sau
Phiên bản trước
programming4:api [2021/03/22 07:53] – [Dành cho nhà phát triển muốn cung cấp API] hoaquynhtim99programming4:api [2023/12/19 08:14] (hiện tại) – [Lệnh gọi API rewrite (không gọi vào /api.php) lỗi 404] hoaquynhtim99
Dòng 2: Dòng 2:
  
 > Hệ thống API được đưa vào kể từ phiên bản 4.5.00 > Hệ thống API được đưa vào kể từ phiên bản 4.5.00
 +
 +Xem mô tả luồng truy vấn thông thường và API như ảnh bên dưới
 +
 +{{ :programming4:luong-api.jpg |}}
  
 ===== Dành cho nhà phát triển sử dụng API ===== ===== Dành cho nhà phát triển sử dụng API =====
 +==== Lưu ý khi sử dụng API ====
 +  - Nếu không bắt buộc không nên sử dụng API (Mặc định NukeViet < 4.5 không cung cấp API, bản NukeViet 4.5 trở đi sẽ không kích hoạt mặc định)
 +  - Tại chức năng **Cấu hình => Cấu hình chung** cần Bật **Remote API** 
 +  - Quyền truy cập API tại phần **Quản trị => Quyền truy cập API** đã chọn đủ API Role có chứa API cần gọi.
 +  - Cấp quyền ít nhất: Một API Roles chỉ nên có các quyền ít nhất, không nên cấp tất cả các quyền. Quyền có thể được thêm vào khi cần thiết và nên được thu hồi khi không còn được sử dụng.
 +  - Quyền truy cập API, nên được giới hạn theo IP, Xóa Quyền truy cập API nếu không dùng nữa.
 +  - Sử dụng HTTPS cho cả website, trong đó có API
 +  - Nếu phải viết thêm API, hãy viết nó đơn giản: Mỗi khi bạn làm cho giải pháp phức tạp hơn một cách “không cần thiết”, bạn cũng có khả năng để lại một lỗ hổng.
  
 ==== Nguyên tắc chung ==== ==== Nguyên tắc chung ====
Dòng 14: Dòng 26:
 [ [
     'apikey' => '...', // Khóa được cung cấp     'apikey' => '...', // Khóa được cung cấp
-    'apisecret' => '...', // Mã bí mật được cung cấp+    'timestamp' => '...', // Thời gian resquest sai lệch với giờ máy chủ không quá 5 giây 
 +    'hashsecret' => '...', // Mã bí mật mỗi lần resquest = password_hash($apisecret . '_' . $timestamp, PASSWORD_DEFAULT);
     'action' => 'GetLesson', // Tên API được list bên dưới     'action' => 'GetLesson', // Tên API được list bên dưới
     'module' => 'elearning', // Module xử lý, ở đây là elearning, để trống thì là API của hệ thống     'module' => 'elearning', // Module xử lý, ở đây là elearning, để trống thì là API của hệ thống
 +    'language' => 'vi' // Bắt buộc nếu API của module trên site đa ngôn ngữ
 ] ]
 </code> </code>
Dòng 52: Dòng 66:
 } }
  
 +$apisecret = '';
 +$timestamp = time();
 $request = [ $request = [
     // Tham số bắt buộc     // Tham số bắt buộc
     'apikey' => '...',     'apikey' => '...',
-    'apisecret' => '...',+    'timestamp' => $timestamp, 
 +    'hashsecret' => password_hash($apisecret '_' $timestamp, PASSWORD_DEFAULT), 
 +    'language' => 'vi',
     'action' => 'CreatArticle',     'action' => 'CreatArticle',
     'module' => 'news'     'module' => 'news'
Dòng 82: Dòng 100:
 <code php> <code php>
 // Các tham số tùy chọn của mỗi API để vào biến $parameters // Các tham số tùy chọn của mỗi API để vào biến $parameters
 +$apisecret = '';
 +$timestamp = time();
 $parameters = []; $parameters = [];
 $request = [ $request = [
     // Tham số bắt buộc     // Tham số bắt buộc
     'apikey' => '...',     'apikey' => '...',
-    'apisecret' => '...',+    'timestamp' => $timestamp, 
 +    'hashsecret' => password_hash($apisecret '_' $timestamp, PASSWORD_DEFAULT), 
 +    'language' => 'vi',
     'action' => 'CreatArticle',     'action' => 'CreatArticle',
     'module' => 'news',     'module' => 'news',
Dòng 119: Dòng 141:
  
  
 +==== API của module ====
  
-===== Dành cho nhà phát triểmuốcung cấp API =====+Trong tài liệu này chúng tôi ví dụ module hiệtại là module **page** đang chuẩbị lậtrình chức năng API.
  
-Để remote api hoạđộng cần đảm bảo các yếu tố sau:+> Lưu ý: Tên module, tên file Api và tên Class phân biệchữ hoa và chữ thường.
  
-  - Tại chức năng **Thiết lập Cross-Site** ở phần **Cấu hình => Thiết lập an ninh** cần tắt bảo vệ ngoài site hoặc thêm tên miền hoặc IP cho phép gọi API +**Bướ1: Tạo thư mụApi để chứa các file Api**
-  - Tại chứnăng **Cấu hình => Cấu hình chung** cần Bật **Remote API**  +
-  - Quyền truy cập API tại phần **Quản trị => Quyền truy cập API** đã chọn đủ API Role có chứa API cần gọi.+
  
-==== API của module ====+Trong thư mục của module tạo thêm thư mục **Api**. Khi đó tồn tại đường dẫn ''modules/page/Api''
  
-Xem hướng dẫn [[programming5:module:api|Module hỗ trợ API]]+**Bước 2: Tạo file trong thư mục Api** 
 + 
 +Mỗi Api sẽ nằm trong một file php nằm trong thư mục Api. Tên file là tên class (phân biệt chữ viết hoa và viết thường). Ví d: 
 + 
 +<file php CreatArticle.php> 
 +<?php 
 + 
 +/** 
 + * @Project NUKEVIET 4.x 
 + * @Author VINADES.,JSC <contact@vinades.vn> 
 + * @Copyright (C) 2014 VINADES ., JSC. All rights reserved 
 + * @License GNU/GPL version 2 or any later version 
 + * @Createdate Jun 20, 2010 8:59:32 PM 
 + */ 
 + 
 +namespace NukeViet\Module\page\Api; 
 + 
 +use NukeViet\Api\Api; 
 +use NukeViet\Api\ApiResult; 
 +use NukeViet\Api\IApi; 
 + 
 +if (!defined('NV_ADMIN') or !defined('NV_MAINFILE')) { 
 +    die('Stop!!!'); 
 +
 + 
 +class CreatArticle implements IApi 
 +
 +    private $result; 
 + 
 +    /** 
 +     * @return number 
 +     */ 
 +    public static function getAdminLev() 
 +    { 
 +        return Api::ADMIN_LEV_MOD; 
 +    } 
 + 
 +    /** 
 +     * @return string 
 +     */ 
 +    public static function getCat() 
 +    { 
 +        return 'System'; 
 +    } 
 + 
 +    /** 
 +     * {@inheritDoc} 
 +     * @see \NukeViet\Api\IApi::setResultHander() 
 +     */ 
 +    public function setResultHander(ApiResult $result) 
 +    { 
 +        $this->result = $result; 
 +    } 
 + 
 +    /** 
 +     * {@inheritDoc} 
 +     * @see \NukeViet\Api\IApi::execute() 
 +     */ 
 +    public function execute() 
 +    { 
 +        // @TODO 
 + 
 +        return $this->result->getResult(); 
 +    } 
 +
 + 
 +</file> 
 + 
 +Giải thích code như sau: 
 + 
 +=== Namespaces === 
 + 
 +<code php> 
 +namespace NukeViet\Module\page\Api; 
 +</code> 
 + 
 +Quy luật: 
 + 
 +<code> 
 +NukeViet\Module\<ModuleFile>\Api 
 +</code> 
 + 
 +''<ModuleFile>'' chính là tên thư mục chứa module, trong ví dụ này là ''page''
 + 
 +Sau khi đặt namespace, ta khai báo sử dụng các class NukeViet Core hỗ trợ
 + 
 +<code php> 
 +use NukeViet\Api\Api; 
 +use NukeViet\Api\ApiResult; 
 +use NukeViet\Api\IApi; 
 +</code> 
 +=== Class Name === 
 + 
 +<code php> 
 +class CreatArticle implements IApi 
 +</code> 
 + 
 +Class cần phải implements lớp IApi, theo đó phải có đủ 3 phương thức 
 + 
 +<code php> 
 +/** 
 + * Lấy được quyền hạn sử dụng của admin 
 + * Admin tối cao, điều hành chung hay quản lý module được sử dụng 
 + */ 
 +public static function getAdminLev(); 
 + 
 +/** 
 + * Danh mục, cũng là khóa ngôn ngữ của API 
 + * Nếu không có danh mục thì trả về chuỗi rỗng 
 + */ 
 +public static function getCat(); 
 + 
 +/** 
 + * Thiết lập trình xử lý kết quả 
 + * 
 + * @param ApiResult $result 
 + */ 
 +public function setResultHander(ApiResult $result); 
 + 
 +/** 
 + * Thực thi API 
 + */ 
 +public function execute(); 
 +</code> 
 + 
 +> Lưu ý: Class name chính là tên file. Ví dụ class name là CreatArticle thì file sẽ là ''module/Page/Api/CreatArticle.php'' 
 + 
 +=== Phương thức getAdminLev === 
 + 
 +Cho biết đối tượng được quyền sử dụng API: 
 + 
 +<code php> 
 +public static function getAdminLev() 
 +
 +    return Api::ADMIN_LEV_MOD; 
 +
 +</code> 
 + 
 +Cần trả về một trong 3 giá trị: 
 + 
 +<code php> 
 +Api::ADMIN_LEV_GOD; // 1: Admin tối cao 
 +Api::ADMIN_LEV_SP; // 2: Điều hành chung 
 +Api::ADMIN_LEV_MOD; // 3: Quản lý module 
 +</code> 
 + 
 +=== Phương thức getCat === 
 + 
 +Cho biết danh mục của API nếu có, nếu API không được xếp danh mục hãy trả về chuỗi rỗng. 
 + 
 +<code php> 
 +public static function getCat() 
 +
 +    return 'System'; 
 +
 +</code> 
 + 
 +=== Phương thức setResultHander === 
 + 
 +<code php> 
 +public function setResultHander(ApiResult $result) 
 +
 +    $this->result = $result; 
 +
 +</code> 
 + 
 +Giữ nguyên code như mẫu, không thay đổi thêm. 
 + 
 +=== Code thực thi Api === 
 + 
 +<code php> 
 +public function execute() 
 +
 +    // Viết code thực thi tại đây 
 + 
 +    return $this->result->getResult(); 
 +
 +</code> 
 + 
 +Code thực thi được viết tự do, và bắt buộc phải trả về thông qua phương thức ''getResult'' của class ''NukeViet\Api\ApiResult'' 
 + 
 +=== Sử dụng các dữ liệu hệ thống === 
 + 
 +  * Lấy biến ''$module_name'' sử dụng lệnh ''$module_name = Api::getModuleName();'' 
 +  * Lấy biến ''$module_info'' sử dụng lệnh ''$module_name = Api::getModuleInfo();''. Các biến ''$module_data, $module_file, $module_upload'' xác định từ ''$module_info''
 +  * Lấy ID của Admin thực hiện API sử dụng lệnh ''$admin_id = Api::getAdminName();'' 
 +  * Lấy Username của Admin thực hiện API sử dụng lệnh ''$admin_username = Api::getAdminId();'' 
 +  * Lấy Cấp bậc của Admin thực hiện API sử dụng lệnh ''$admin_level = Api::getAdminLev();'' 
 +  * Các biến hệ thống như ''$nv_Lang, $nv_Request, $db, $nv_Cache, ...'' có thể gọi global như thông thường. 
 + 
 +=== Cách trả dữ liệu về === 
 + 
 +Message thông báo: 
 + 
 +<code php> 
 +$this->result->setMessage($nv_Lang->getModule('empty_bodytext')); 
 +</code> 
 + 
 +Mã lỗi (nếu có): 
 + 
 +<code php> 
 +$this->result->setCode($code); 
 +</code> 
 + 
 +Đánh dấu thành công: 
 + 
 +<code php> 
 +$this->result->setSuccess(); 
 +</code> 
 + 
 +Đánh dấu lỗi: 
 + 
 +<code php> 
 +$this->result->setError(); 
 +</code> 
 + 
 +Các dữ liệu khác: 
 + 
 +<code php> 
 +$this->result->set($key, $value); 
 +</code> 
 + 
 +** Bước 3 thêm giá  trị api vào file ngôn ngữ của module ** 
 +  * $lang_module['api_modulename'] 
 +  * $lang_module['api_modulename_class']
  
 ==== API của hệ thống ==== ==== API của hệ thống ====
Dòng 139: Dòng 384:
   * namespace là ''namespace NukeViet\Api;''   * namespace là ''namespace NukeViet\Api;''
  
 +
 +==== Cách gọi API nội bộ ====
 +
 +Ta có thể dùng hàm ''nv_local_api'', cụ thể như sau
 +<code php>
 +$return = nv_local_api($cmd, $params, $adminidentity = '', $module = '');
 +</code>
 +
 +Trong đó:
 +  * $return: là kết quả API trả về
 +  * $cmd: là tương ứng với action khi remote
 +  * $params: là mảng data nó sẽ được chuyển thành biến $_POST
 +  * $adminidentity: là userid hoặc username của admin
 +  * $module: tương ứng với module khi remote
 +
 +Ví dụ: Với cách gọi qua CURL thông thường, ta cần phải làm các bước sau:
 +<code php>
 +$agent = 'NukeViet Remote API Lib';
 +$safe_mode = (ini_get('safe_mode') == '1' || strtolower(ini_get('safe_mode')) == 'on') ? 1 : 0;
 +$open_basedir = ini_get('open_basedir') ? true : false;
 +
 +$ch = curl_init();
 +curl_setopt($ch, CURLOPT_URL, '...'//URL của API);
 +curl_setopt($ch, CURLOPT_HEADER, 0);
 +
 +if (!$safe_mode and !$open_basedir) {
 +     curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
 +     curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
 +}
 +
 +$params= [
 +    'apikey' => '...', // Khóa được cung cấp
 +    'timestamp' => '...', // Thời gian resquest sai lệch với giờ máy chủ không quá 5 giây
 +    'hashsecret' => '...', // Mã bí mật mỗi lần resquest = password_hash($apisecret . '_' . $timestamp, PASSWORD_DEFAULT);
 +    'action' => 'GetUsername', // Tên API hoặc action khi remote
 +    'module' => 'user', // Module xử lý, ở đây là user, để trống thì là API của hệ thống
 +    'language' => 'vi' // Bắt buộc nếu API của module trên site đa ngôn ngữ
 +    
 +    //Các dữ liệu cần thiết, ví dụ ở đây ta sẽ truyền userid
 +    'userid' => $userid
 +];
 +
 +$str = http_build_query($request);
 +curl_setopt($ch, CURLOPT_TIMEOUT, 20);
 +curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 +curl_setopt($ch, CURLOPT_USERAGENT, $agent);
 +curl_setopt($ch, CURLOPT_POST, sizeof($request));
 +curl_setopt($ch, CURLOPT_POSTFIELDS, $str);
 +$return = curl_exec($ch);  //Dữ liệu API sẽ trả về
 +curl_close($ch);
 +</code>
 +
 +Với hàm ''nv_local_api'', ta sử dụng:
 +<code php>
 +$params= [
 +     'userid' => $userid
 +];
 +$return = nv_local_api('GetUsername', $params, 'admin', 'user');
 +/*
 + Với:
 +  * $return: Dữ liệu API sẽ trả về
 +  * 'GetUsername': Tên API hoặc action khi remote
 +  * $params: Mảng dữ liệu truyền vào API
 +  * 'admin': username của tài khoản admin
 +  * 'user': Module xử lý
 +*/
 +</code>
 +Có thể xem thêm về hàm ''nv_local_api'' tại: ''.../includes/function.php''
 +
 +===== Gỡ lỗi API =====
 +
 +==== Lệnh gọi API rewrite (không gọi vào /api.php) lỗi 404 ====
 +
 +
 +Kiểm tra xem máy chủ có hỗ trợ rewrite hay không là điều kiện đầu tiên. Nếu có hỗ trợ thì check lần lượt các hướng bên dưới.
 +
 +**Nếu máy chủ sử dụng Apache**
 +
 +  * Tìm trong httpd.conf (hoặc các file config tương đương) thẻ ''%%<Directory "path/to/your/dir">%%'' nếu có ''%%Options .... MultiViews%%'' thì xóa MultiViews sau đó khởi động lại apache.
 +  * Tìm trong .htaccess ngay thư mục gốc website nếu không có thì thêm vào đoạn sau
 +
 +<code>
 +<IfModule mod_negotiation.c>
 +    Options -MultiViews
 +</IfModule>
 +</code>
 + 
 +  * Nếu thêm vào vẫn không hoạt động thì cần cài thêm [[https://httpd.apache.org/docs/2.4/mod/mod_negotiation.html|mod_negotiation]]
  
  
programming4/api.1616374407.txt.gz · Sửa đổi lần cuối: 2021/03/22 07:53 bởi hoaquynhtim99