APP模擬器:Start BlueStacks;
第一、APP接口簡介
1.1、客戶端app通信
這種通信模式類似於BS架構系統相似,但是有區別:
(1):客戶端請求地址是不可見的,是封裝在APP中的;
(2):BS架構返回的是HTML格式數據,而APP返回的是XML和JSON數據格式。
1.2、app通信格式的區別:
XML定義:擴展標記語言,可以用來標記數據、定義數據類型,是一種允許用戶對自己的標記語言進行定義的源語言。XML格式統一,跨平臺和語言,非常適合數據傳輸和通信。(XML節點不能爲數字)
<?xml version="1.0" encoding="UTF-8"?>
<item>
<title>singwa</title>
<test id="1"/>
<address>beijing</address>
</item>
JSON定義:JSON一種輕量級的數據交換格式,具有良好的可讀和便於 快速編寫的特徵。可以在不同的平臺之間進行數據交換。json數據兼容性高、完全獨立與語言文本格式。
(1):可讀性方面 ---> XML比較好;
(2):生成數據方面 ----> json比較好;
(3):傳輸速度方面 ----> json比較好;
第二、封裝通信接口數據方法:
1.1、PHP生成JSON數據(json_encode只支持UTF-8)
1.2、通信數據標準模式
code 狀態碼(200,400等)
message 提示信息(郵箱格式不正確:數據返回成功等)
data 返回數據
1.3、封裝通信數據方式
JSON封裝通信方式:
<?php
class Pesponse {
/**
* [通過json方式輸出通信數據]
* @param integer $code 狀態碼
* @param string $message 提示信息
* @param array $data 數據
*/
public static function json($code, $message='', $data=array()) {
if (!is_numeric($code)) {
return '';
}
$result = array(
'code'=>$code,
'message'=>$message,
'data'=>$data
);
echo json_encode($result);
exit;
}
}
XML封裝通信:<?php
class Pesponse {
/**
* [通過json方式輸出通信數據]
* @param integer $code 狀態碼
* @param string $message 提示信息
* @param array $data 數據
*/
public static function xmlEncode($code, $message='', $data=array()) {
if (!is_numeric($code)) {
return '';
}
$result = array(
'code'=>$code,
'message'=>$message,
'data'=>$data
);
header("Content-Type:text/xml");
$xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
$xml .= "<root>\n";
$xml .= self::xmlToEocode($result);
$xml .= "</root>";
echo $xml;
}
public static function xmlToEocode($data) {
$xml = $attr = "";
foreach($data as $key=>$val) {
if (is_numeric($key)) {
$attr = " id='{$key}'";
$key = "item";
}
$xml .= "<{$key}{$attr}>";
$xml .= is_array($val)?self::xmlToEocode($val):$val;
$xml .= "</{$key}>";
}
return $xml;
}
}
$data = array(
'id'=>"1",
'name'=>'singwa',
'type'=>array(1,2,3),
);
Pesponse::xmlEncode(200,'success',$data);
綜合通信方式封裝:(response.php)
<?php
class Pesponse {
const JSON = "json";
/**
* [通過json方式輸出通信數據]
* @param integer $code 狀態碼
* @param string $message 提示信息
* @param array $data 數據
* @param string $type 數據類型
*/
public static function show($code, $message='', $data=array(), $type=self::JSON) {
if (!is_numeric($code)) {
return "";
}
$type = isset($_GET['type']) ? $_GET['type'] : self::JSON;
$result = array(
'code'=>$code,
'message'=>$message,
'data'=>$data,
);
if ($type == "json") {
self::json($code, $message, $data); exit;
} elseif($type == "array") {
var_dump($result);
} elseif($type == "xml") {
self::xmlEncode($code, $message, $data);
exit;
} else {
//TODO
}
}
/**
* [通過json方式輸出通信數據]
* @param integer $code 狀態碼
* @param string $message 提示信息
* @param array $data 數據
*/
public static function json($code, $message='', $data=array()) {
if (!is_numeric($code)) {
return '';
}
$result = array(
'code'=>$code,
'message'=>$message,
'data'=>$data
);
echo json_encode($result);
exit;
}
public static function xmlEncode($code, $message='', $data=array()) {
if (!is_numeric($code)) {
return '';
}
$result = array(
'code'=>$code,
'message'=>$message,
'data'=>$data
);
header("Content-Type:text/xml");
$xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
$xml .= "<root>\n";
$xml .= self::xmlToEocode($result);
$xml .= "</root>";
echo $xml;
}
public static function xmlToEocode($data) {
$xml = $attr = "";
foreach($data as $key=>$val) {
if (is_numeric($key)) {
$attr = " id='{$key}'";
$key = "item";
}
$xml .= "<{$key}{$attr}>";
$xml .= is_array($val)?self::xmlToEocode($val):$val;
$xml .= "</{$key}>";
}
return $xml;
}
}
$data = array(
'id'=>"1",
'name'=>'singwa',
'type'=>array(1,2,3),
'test'=>array(4,5,6=>array(123,'ssss'))
);
Pesponse::show(200,'success',$data);
2.1、PHP生成XML數據:
2.1.1、組裝字符串
<?php
class Pesponse {
public static function xml() {
header("Content-Type:text/xml");
$xml = "<?xml version='1.0' encoding='UTF-8'?>\n";
$xml .= "<root>\n";
$xml .= "<code>200</code>\n";
$xml .= "<message>數據返回成功</message>\n";
$xml .= "<data>\n";
$xml .= "<id>1</id>\n";
$xml .= "<name>singwa</name>\n";
$xml .= "</data>\n";
$xml .= "</root>";
echo $xml;
}
}
Pesponse::xml();
2.1.2、使用系統類(PHP開發手冊中查找)
DOMDocument XMLWriter SimpleXML
第三、核心技術
3.1、靜態緩存(文件,file.php)
<?php
class File {
private $_dir;
const EXT = '.txt';
public function __construct(){
$this->_dir = dirname(__FILE__).'/file/';
}
/**
* @param [string] $key [文件名]
* @param string $value [數據]
* @param string $path [文件路徑]
* @return [return] [字節數 或者false]
*/
public function cacheData($key, $value = '', $cacheTime = 0) {
$filename = $this->_dir.$key.self::EXT;
if ($value !== "") {//將value值寫入緩存
if (is_null($value)) {//當 $value爲null時,刪除緩存
return @unlink($filename);
}
$dir = dirname($filename);
if (!is_dir($dir)) {
mkdir($dir,0777);
}
//"%011d"表示不是11位,補0
$cacheTime = sprintf('%011d', $cacheTime);
//如果成功返回數據的字節數,沒有成功返回false
return file_put_contents($filename, $cacheTime.json_encode($value));
}
//讀取緩存數據(在調用cacheData方法$value不寫時)
if (!is_file($filename)) {
return FALSE;
}
//獲取緩存內容
$contents = file_get_contents($filename);
//獲取緩存時間
$cacheTime = (int)substr($contents,0,11);
//獲取緩存內容
$value = substr($contents,11);
//判斷緩存失效時間
if($cacheTime != 0 && $cacheTime+filemtime($filename)<time()) {
unlink($filename);
return FALSE;
}
return json_decode($value,true);
}
}
第三、定時任務
1.定時任務命令
1.定時任務服務提供crontab命令來設定服務
2.crontab -e //編輯某個用戶的cron服務
3.crontab -l //列出某個用戶cron服務的詳細內容
4.crontab -r //刪除某個用戶的cron服務
2、定時任務crontab格式
3、定時任務的crontab例子
第四、APP接口實例
1、單例模式鏈接數據庫(db.php)
1.1、單例模式三大原則
(1):構造函數需要標記爲非public(防止外部使用new操作符創建對象),單例類不能在其他類中實例化,只能被其自身實例化;
(2):擁有一個保存類的實例的靜態成員變量$_instance;
(3):擁有一個訪問這個實例的公共的靜態方法。
<?php
class Db {
static private $_instance;
static private $_connectSource;
private $dbConfig = array(
'host' => '127.0.0.1',
'user' => 'root',
'password'=> 'root',
'database'=> 'video',
);
private function __construct() {
}
//公共的靜態方法
static public function getInstance() {
if (!(self::$_instance instanceof self)) {
self::$_instance = new self();
}
return self::$_instance;
}
//連接數據庫
public function connect() {
if (!self::$_connectSource) {
self::$_connectSource = mysql_connect($this->_dbConfig['host'], $this->_dbConfig['user'], $this->_dbConfig['password']);
if (self::$_connectSource) {
throw new Exception('mysql connect error'.mysql_error());
}
mysql_select_db($this->_dbConfig['database'], self::$_connectSource);
mysql_quert('set names UTF-8', self::$_connectSource);
}
return self::$_connectSource;
}
}
//連接數據庫
$connect = Db::getInstance()->connect();
2、首頁APP接口開發
方案一、 讀取數據庫方式開發 首頁接口(應用場景:數據時效性比較高的系統)
<?php
require_once('./response.php');
require_once('./db.php');
//判斷鏈接合法性
$page = isset($_GET['page']) ? $_GET['page'] : 1;
$pageSize = isset($_GET['pagesize']) ? $_GET['pagesize'] : 1;
if (!is_numeric($page) || !is_numeric($pageSize)) {
return Response::show(401,'數據不合法');
}
$offset = ($page-1) * $pageSize;
$sql = "select * from video where status = 1 order by orderby desc limit ".$offset.",".$pageSize;
//連接數據庫
try {
$connect = Db::getInstance()->connect();
} catch(Exception $e) {
return Response::show(403, '數據庫鏈接失敗');
}
$result = mysql_query($sql, $connect);
$videos = array();
while ($video = mysql_fetch_assoc($result)) {
$videos[] = $video;
}
if ($videos) {
return Response::show(200, '首頁獲取數據成功', $videos);
} else {
return Response::show(400, '首頁獲取數據失敗', $videos);
}
方案二、讀取緩存方式開發首頁接口(用途:減少數據庫壓力)(文件緩存)
<?php
require_once('./response.php');
require_once('./db.php');
require_once('./file.php');
//判斷鏈接合法性
$page = isset($_GET['page']) ? $_GET['page'] : 1;
$pageSize = isset($_GET['pagesize']) ? $_GET['pagesize'] : 1;
if (!is_numeric($page) || !is_numeric($pageSize)) {
return Response::show(401,'數據不合法');
}
$offset = ($page-1) * $pageSize;
$sql = "select * from video where status = 1 order by orderby desc limit ".$offset.",".$pageSize;
$cache = new File();
$videos = array();
if (!$videos = $cache->cacheData('index_cache'.$page.'-'.$pageSize)) {
//連接數據庫
try {
$connect = Db::getInstance()->connect();
} catch(Exception $e) {
return Response::show(403, '數據庫鏈接失敗');
}
$result = mysql_query($sql, $connect);
while ($video = mysql_fetch_assoc($result)) {
$videos[] = $video;
}
if ($videos) {
$cache->cacheData('index_cache'.$page.'-'.$pageSize,$videos,1200);
}
}
if ($videos) {
return Response::show(200, '首頁獲取數據成功', $videos);
} else {
return Response::show(400, '首頁獲取數據失敗', $videos);
}
方案三、定時讀取緩存方式開發首頁接口
<?php
//讓crontab定時執行的腳本程序------ */5 * * * * /usr/bin/php /data/www/app/corn.php
require_once('./db.php');
require_once('./file.php');
$sql = "select * from video where status = 1 order by orderby desc";
try {
$connect = Db::getInstance()->connect();
} catch(Exception $e) {
file_put_contents('./logs/'.date('y-m-d').'.txt',$e->getMessage());
return;
}
$result = mysql_query($sql, $connect);
$videos = array();
while($video = mysql_fetch_assoc($result)) {
$videos[] = $video;
}
$file = new File();
if($videos) {
$file->cacheData('index_cron_cache',$videos);
} else {
file_put_contents('/logs/'.date('y-m-d').'.txt',"沒有相關數據");
}
return;
1、APP版本升級分析以及數據表設計
檢測升級:首先開啓APP請求初始化接口init.php,檢測是否更新,如果更新下載最新的源碼包,替換原來的APK,否的話直接返回首頁;
初始化接口init.php要傳遞的參數:app_id:客戶端id(1.安卓,2.iPhone)、version_id:(版本號)
2、升級接口開發和演示
處理接口業務(common.php)
<?php
/**
* 處理接口公共業務
*/
require_once('./response.php');
require_once('./db.php');
class Common {
public $params;
public $app;
public function check() {
$this->params['app_id'] = $appId = isset($_POST['app_id']) ? $_POST['app_id'] : '';
$this->params['version_id'] = $versionId = isset($_POST['version_id']) ? $_POST['version_id'] : '';
$this->params['version_mini'] = $versionMini = isset($_POST['version_mini']) ? $_POST['version_mini'] : '';
$this->params['did'] = $did = isset($_POST['did']) ? $_POST['did'] : '';
$this->params['encrypt_did'] = $encryptDid = isset($_POST['encrypt_did']) ? $_POST['encrypt_did'] : '';
if (!is_numeric($appId) || !is_numeric($versionId)) {
return Response::show(401, '參數不合法');
}
//判斷APP是否需要加密
$this->app = $this->getApp($appId);
if (!$this->app) {
return Response::show(402, 'app_id不存在');
}
if ($this->app['is_encryption'] && $encryptDid != md5($did . $this->app['key'])) {
return Response::show(403, '沒有權限');
}
}
public function getApp($id) {
$sql = "SELECT * FROM 'app' WHERE id = ".$id." AND status = 1 LIMIT 1";
$connect = Db::getInstance();->connect();
$result = mysql_query($sql, $connect);
return mysql_fetch_assoc($result);
}
}
判斷是否升級(init.php)
<?php
require_once('./common.php');
require_once('./');
class Init extends Common{
public function index() {
$this->check();
//獲取版本升級信息
$versionUpgrade = $this->getversionUpgrade($this->app['id']);
if ($versionUpgrade) {
if ($versionUpgrade['type'] && $this->params['version_id'] < $versionUpgrade['version_id']) {
//需要升級
$versionUpgrade['is_upload'] = $versionUpgrade['type'];
} else {
//不需要升級
$versionUpgrade['is_upload'] = 0;
}
return Response::show(200, '版本升級信息獲取成功', $versionUpgrade);
} else{
return Response::show(400, '版本升級信息獲取失敗');
}
}
}
第五、APP錯誤日誌
1、面臨的錯誤問題
1.1、APP強退;
1.2、數據加載失敗;
1.3、APP潛在問題;
錯誤日誌表:
錯誤日誌類:
<?php
require_once('./common.php');
require_once('./db.php');
class ErrorLog extends Common {
public function index() {
$this->check();
$errorLog = isset($_POST['error_log']) ? $_POST['error_log'] : '';
if (!$errorLog) {
return Response::show(401, '日誌爲空');
}
$sql = "INSERT INTO
error_log(
'app_id',
'did',
'version_id',
'version_mini',
'error_log',
'crete_time')
VALUES(
".$this->params['app_id'].",
'".$this->params['did']."',
".$this->params['version_id'].",
".$this->params['version_mini'].",
'".$error_log."',
".time()."
)";
$connect = Db::getInstance()->connect();
if (mysql_quert($sql, $connect)) {
return Response::show(200, '錯誤信息插入成功');
} else {
return Response::show(200, '錯誤信息插入失敗');
}
}
}