Sub.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. <?php
  2. /**
  3. * Sub.php UTF-8
  4. * 分包类
  5. *
  6. * @date : 2016年12月8日下午10:09:43
  7. *
  8. * @license 这不是一个自由软件,未经授权不许任何使用和传播。
  9. * @author : wuyonghong <wyh@huosdk.com>
  10. * @version : HUOSDK 7.0
  11. * @modified: 2016年12月8日下午10:09:43
  12. */
  13. class Sub {
  14. private $rootpath; /* 源路径 */
  15. private $srcpath; /* 源路径 */
  16. private $destpath; /* 目标路径 */
  17. private $byteSize;
  18. private $system; /* 系统 ios:ios and:android */
  19. private $agentgame;
  20. private $pinyin;
  21. private $ip;
  22. private $sign;
  23. private $prj_id;
  24. private $downurl;
  25. private $iparr;
  26. private $imageurl; /* logo路径 */
  27. private $redicturl; /* webclip跳转路径 */
  28. private $oldgame_arr = array();
  29. public function __construct($url = '', $prj_id = '', $downurl = '', $iparr = array()) {
  30. $this->iparr = $iparr;
  31. $_urldata = file_get_contents("php://input");
  32. $_urldata = get_object_vars(json_decode($_urldata));
  33. $this->pinyin = base64_decode($_urldata['p']);
  34. $this->agentgame = base64_decode($_urldata['a']);
  35. $this->sign = base64_decode($_urldata['o']);
  36. $this->ip = $this->getIp();
  37. $this->checkPackage($this->pinyin);
  38. $this->rootpath = $url;
  39. $this->imageurl = isset($_urldata['image']) ? $_urldata['image'] : '';
  40. $this->redicturl = isset($_urldata['rurl']) ? $_urldata['rurl'] : '';
  41. $this->downurl = isset($_urldata['ipa_url']) ? $_urldata['ipa_url'] : '';
  42. $this->prj_id = !empty($_urldata['prj_id']) ? $_urldata['prj_id'] : $prj_id;
  43. if (empty($url)) {
  44. $this->rootpath = dirname(__DIR__).'/sdkgame/';
  45. }
  46. $_pinyinarr = explode('/', $this->pinyin);
  47. if ('ios' == $this->system) {
  48. $this->srcpath = $this->rootpath.$this->pinyin.DIRECTORY_SEPARATOR.$_pinyinarr[0].'.ipa';
  49. $this->destpath = $this->rootpath.$this->pinyin.DIRECTORY_SEPARATOR.$this->agentgame.'.ipa';
  50. } else {
  51. $this->srcpath = $this->rootpath.$this->pinyin.DIRECTORY_SEPARATOR.$_pinyinarr[0].'.apk';
  52. $this->destpath = $this->rootpath.$this->pinyin.DIRECTORY_SEPARATOR.$this->agentgame.'.apk';
  53. }
  54. }
  55. function subPack() {
  56. /* 1 校验来源合法性 返回 -6 */
  57. if (false === $this->checkIp()) {
  58. return -6;
  59. }
  60. /* 生成mobileconfig文件 */
  61. if (!empty($this->redicturl)) {
  62. return $this->createWebclip();
  63. }
  64. /* 2 检查参数是否合法 返回 -3 */
  65. if (false === $this->checkParam()) {
  66. return -3;
  67. }
  68. /* 3 检查签名是否合法 返回-4 */
  69. if (false === $this->checkToken()) {
  70. return -4;
  71. }
  72. /* 4 检查母包是否存在 返回-5 若是检查母包 */
  73. $_rs = $this->checkSrc();
  74. if (0 !== $_rs) {
  75. return $_rs;
  76. }
  77. /* 5 检查目标包是否存在 若目标包为母包 则返回目标包信息 */
  78. $_rs = $this->checkDest();
  79. if (0 !== $_rs) {
  80. return $_rs;
  81. }
  82. /* 6 若为android 则创建目标包 */
  83. $_rs = $this->createDest();
  84. return $_rs;
  85. }
  86. /* 1 校验来源合法性 返回 -6 */
  87. function checkIp() {
  88. $_rdata = false;
  89. if (in_array($this->ip, $this->iparr)) {
  90. $_rdata = true;
  91. }
  92. return $_rdata;
  93. }
  94. /* 2 检查参数是否合法 返回 -3 */
  95. function checkParam() {
  96. if (empty($this->pinyin) || empty($this->agentgame)) {
  97. return false;
  98. }
  99. return true;
  100. }
  101. /* 3 检查签名是否合法 返回-4 */
  102. function checkToken() {
  103. $_sign = md5(md5($this->pinyin.$this->agentgame).'resub');
  104. if ($_sign != $this->sign) {
  105. return false;
  106. }
  107. return true;
  108. }
  109. /* 4 检查母包是否存在 */
  110. function checkSrc() {
  111. if (!file_exists($this->srcpath)) {
  112. if (!file_exists($this->rootpath.$this->pinyin)) {
  113. mkdir($this->rootpath.$this->pinyin, 0777, true);
  114. }
  115. if ($this->srcpath == $this->destpath) {
  116. return 1;
  117. }
  118. return -5; // 游戏原包不存在
  119. }
  120. return 0;
  121. }
  122. /* 5 检查目标包是否存在 若目标包为母包 则返回目标包信息 */
  123. function checkDest() {
  124. if (file_exists($this->destpath)) {
  125. if ($this->srcpath == $this->destpath) {
  126. $_data = $this->getPackageinfo($this->srcpath);
  127. return $_data;
  128. }
  129. return 2; // 已分包
  130. }
  131. return 0;
  132. }
  133. /* 6 分包 */
  134. function createDest() {
  135. if ('ios' == $this->system) {
  136. /* ios包不需要复制包 */
  137. return 1;
  138. }
  139. if (!copy($this->srcpath, $this->destpath)) {
  140. return -1;
  141. }
  142. $_rs = $this->writeTodest();
  143. return $_rs;
  144. }
  145. function writeTodest() {
  146. $_arr = explode('_', $this->agentgame);
  147. $_cnt = count($_arr);
  148. if ($_cnt >= 2) {
  149. if (in_array($_arr[$_cnt - 2], $this->oldgame_arr)) {
  150. return $this->oldSub();
  151. }
  152. $huomark = md5("p".$this->prj_id."g".$_arr[$_cnt - 2]."a".$_arr[$_cnt - 1]);
  153. } else {
  154. $huomark = md5("p".$this->prj_id.$this->agentgame);
  155. }
  156. $en_ag = $this->rsa_pri_encrypt($this->agentgame);
  157. $channelname = "META-INF/gamechannel";
  158. $huosdk = "META-INF/huosdk_".$huomark;
  159. $zip = new ZipArchive();
  160. if ($zip->open($this->destpath) === true) {
  161. $_rs = $zip->addFromString(
  162. $channelname, json_encode(
  163. array(
  164. 'agentgame' => $en_ag
  165. )
  166. )
  167. );
  168. $zip->addFromString(
  169. $huosdk, json_encode(
  170. array(
  171. 'agentgame' => $huomark
  172. )
  173. )
  174. );
  175. if (false === $_rs) {
  176. unlink($this->destpath);
  177. return -2;
  178. }
  179. $zip->close();
  180. $_rs = 1;
  181. } else {
  182. $_rs = -2;
  183. }
  184. return $_rs;
  185. }
  186. function rsa_pri_encrypt($prestr) {
  187. $private_key_path = dirname(dirname(__DIR__)).'/../data/conf/extra/key/rsa_private_key.pem';
  188. $private_key = file_get_contents($private_key_path);
  189. $private_key = str_replace("-----BEGIN RSA PRIVATE KEY-----", "", $private_key);
  190. $private_key = str_replace("-----END RSA PRIVATE KEY-----", "", $private_key);
  191. $private_key = str_replace("\n", "", $private_key);
  192. $private_key = "-----BEGIN RSA PRIVATE KEY-----".PHP_EOL.wordwrap($private_key, 64, "\n", true).PHP_EOL
  193. ."-----END RSA PRIVATE KEY-----";
  194. $pkeyid = openssl_get_privatekey($private_key);
  195. if ($pkeyid) {
  196. openssl_private_encrypt($prestr, $encodestr, $pkeyid);
  197. } else {
  198. return false;
  199. }
  200. openssl_free_key($pkeyid);
  201. $encodestr = base64_encode($encodestr);
  202. return $encodestr;
  203. }
  204. function checkPackage($pinyin) {
  205. if (empty($pinyin)) {
  206. $_pinyin = $this->pinyin;
  207. } else {
  208. $_pinyin = $pinyin;
  209. }
  210. /* pinyin ios_demoios_101/5 */
  211. $_parr = explode('/', $_pinyin);
  212. $_iarr = explode('_', $_parr[0]);
  213. $this->system = 'and';
  214. $_cnt = count($_iarr);
  215. if ($_cnt >= 2) {
  216. if ('ios' == strtolower(substr($_iarr[$_cnt - 2], -3))) {
  217. $this->system = 'ios';
  218. }
  219. }
  220. }
  221. public function getIp($type = 0, $adv = false) {
  222. $type = $type ? 1 : 0;
  223. $ip = null;
  224. if ($adv) {
  225. if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
  226. $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
  227. $pos = array_search('unknown', $arr);
  228. if (false !== $pos) {
  229. unset($arr[$pos]);
  230. }
  231. $ip = trim(current($arr));
  232. } elseif (isset($_SERVER['HTTP_CLIENT_IP'])) {
  233. $ip = $_SERVER['HTTP_CLIENT_IP'];
  234. } elseif (isset($_SERVER['REMOTE_ADDR'])) {
  235. $ip = $_SERVER['REMOTE_ADDR'];
  236. }
  237. } elseif (isset($_SERVER['REMOTE_ADDR'])) {
  238. $ip = $_SERVER['REMOTE_ADDR'];
  239. }
  240. // IP地址合法验证
  241. $long = sprintf("%u", ip2long($ip));
  242. $ip = $long
  243. ? array(
  244. $ip,
  245. $long
  246. )
  247. : array(
  248. '0.0.0.0',
  249. 0
  250. );
  251. return $ip[$type];
  252. }
  253. /* 获取包体信息 */
  254. function getPackageinfo($file) {
  255. if ('ios' == $this->system) {
  256. $_rdata = $this->getIpainfo($file);
  257. } else {
  258. $_rdata = $this->getApkinfo($file);
  259. }
  260. return json_encode($_rdata);
  261. }
  262. function getApkinfo($file) {
  263. include 'ApkParser.php';
  264. include 'FilesizeHelper.php';
  265. $data = array();
  266. $appObj = new \ApkParser();
  267. $fz = new FilesizeHelper();
  268. $res = $appObj->open($file);
  269. $data['appname'] = $appObj->getAppName(); // 应用名称
  270. $data['pakagename'] = $appObj->getPackage(); // 应用包名
  271. $data['vername'] = $appObj->getVersionName(); // 版本名称
  272. $data['verid'] = $appObj->getVersionCode(); // 版本代码
  273. $data['size'] = $fz->getFileSize($file, false);
  274. return $data;
  275. }
  276. function getIpainfo($file) {
  277. include 'IpaParser.php';
  278. include 'FilesizeHelper.php';
  279. /* 生成 XML文件 */
  280. $_rdata['size'] = '0K';
  281. $appObj = new IpaParser();
  282. $res = $appObj->parse($file);
  283. $data['appname'] = $appObj->getAppName();
  284. $data['pakagename'] = $appObj->getPackage();
  285. $data['vername'] = $appObj->getVersion();
  286. $data['verid'] = '1'; // 版本代码
  287. $fz = new FilesizeHelper();
  288. $data['size'] = $fz->getFileSize($file, false);
  289. $path = $this->rootpath.$this->pinyin.DIRECTORY_SEPARATOR.$this->agentgame.'.plist';
  290. $appObj->createPlist($path, $this->downurl, $data, $this->imageurl);
  291. return $data;
  292. }
  293. function createWebclip() {
  294. if (empty($this->imageurl) || empty($this->redicturl)) {
  295. return -1;
  296. }
  297. include 'IpaParser.php';
  298. /* 生成 XML文件 */
  299. $_rdata['size'] = '0K';
  300. $appObj = new IpaParser();
  301. $res = $appObj->parse($this->srcpath);
  302. $data['appname'] = $appObj->getAppName();
  303. $data['pakagename'] = $appObj->getPackage();
  304. $path = $this->rootpath.'ios.mobileconfig';
  305. $appObj->createWebclip($path, $this->imageurl, $this->redicturl, $data);
  306. return 1;
  307. }
  308. function oldSub() {
  309. $agentgame = $this->agentgame;
  310. $newfile = $this->destpath;
  311. $channelname = "META-INF/gamechannel";
  312. $zip = new ZipArchive;
  313. if ($zip->open($newfile) === true) {
  314. $zip->addFromString($channelname, json_encode(array('agentgame' => $agentgame)));
  315. $zip->close();
  316. $return = 1;
  317. } else {
  318. $return = -2;
  319. }
  320. return $return;
  321. }
  322. }