PHP开发app接口

本文介绍了APP接口的设计与实现过程,包括客户端与服务器之间的通信原理、数据格式的选择(XML与JSON对比)、通信接口数据的封装方法,以及如何利用PHP生成JSON和XML数据。此外,还探讨了单例模式数据库连接、首页接口开发的不同方案、APP版本升级接口的设计,并讨论了错误日志记录的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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;


第四、APP版本升级以及APP演示

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, '错误信息插入失败');
		}
	}
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值