TeachingCommand.php 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. <?php
  2. /**
  3. * 批量生成物理教师讲案(新版)
  4. * User: Administrator
  5. * Date: 2021/3/24
  6. * Time: 17:57
  7. */
  8. require_once __DIR__.'/../controllers/TeachingPhysics.php';
  9. class TeachingCommand extends CConsoleCommand
  10. {
  11. protected $busConnObj = null;//业务数据库连接对象
  12. protected $busDbTime = 0;//业务数据库连接时间
  13. protected $schConnObj = null;//学校数据库连接对象
  14. protected $schDbTime = 0;//学校数据库连接时间
  15. protected $databaseInfo = array();//学校数据库连接信息
  16. protected $dbTimeout = 28;//数据库超时时间
  17. public function init() {
  18. parent::init();
  19. @ini_set('memory_limit', '1024M');
  20. set_time_limit(0);
  21. }
  22. public function actionTask($YII_ENV = 'production')
  23. {
  24. //需要生成的学校考试
  25. $schoolRelExam = $this->getNeedSchoolExam();
  26. if (!$schoolRelExam) {
  27. $this->showMsg(1, '没有需要处理的考试');
  28. return '';
  29. }
  30. $schoolIds = array_keys($schoolRelExam);
  31. $this->showMsg(1, '共有' . count($schoolIds) . '个学校需要处理 .....');
  32. //查询学校数据库连接地址
  33. $schoolDatabases = $this->getSchoolDatabases($schoolIds);
  34. foreach ($schoolRelExam as $schoolId => $examRelClass) {
  35. $this->showMsg(1, '当前学校ID:' . $schoolId . ' .......');
  36. $this->databaseInfo = isset($schoolDatabases[$schoolId]) ? $schoolDatabases[$schoolId] : array();
  37. if (!$this->databaseInfo) {
  38. $this->showMsg(1, '学校ID:' . $schoolId . '没有数据库连接信息');
  39. continue;
  40. }
  41. //连接学校数据库
  42. $this->schConnObj = null;
  43. $this->schConnObj = $this->getSchConnObj();
  44. if (!$this->schConnObj) {
  45. $this->showMsg(1, '学校ID:' . $schoolId . '数据库连接失败!!!!!');
  46. continue;
  47. }
  48. MyActiveRecord::$schoolId = $schoolId;
  49. foreach ($examRelClass as $examGroupId => $classAndId) {
  50. $classStr = $classAndId['class_ids'];
  51. $tableId = $classAndId['id'];//表主键ID
  52. $classNameArr = $this->getClassName($classAndId);
  53. $this->showMsg(1, '当前考试组ID:' . $examGroupId . ' .......');
  54. $examInfoArr = $this->getNeedExamIds($examGroupId, $classStr);
  55. if (!$examInfoArr) {
  56. $this->showMsg(1, '当前考试组ID:' . $examGroupId . '没有可以生产的教学宝');
  57. continue;
  58. }
  59. $pdfPathArr = array();
  60. foreach ($examInfoArr as $examId => $examInfo) {
  61. $time = microtime(true);
  62. $this->showMsg(1, '当前考试ID:' . $examId . ' .......');
  63. //更新生成中状态
  64. $bool = $this->updateStatus($tableId, 4);
  65. if ($bool === false) {
  66. $pdfPathArr = array();
  67. break;
  68. }
  69. echo '开始生成教学宝PDF......' . PHP_EOL;
  70. //生成PDF
  71. $bool = $this->getPdf($pdfPathArr,$tableId,$schoolId,$examId,$examInfo['class_id']);
  72. if ($bool === false) {
  73. $pdfPathArr = array();
  74. break;
  75. }
  76. echo '生成一个PDF耗时:' . round(microtime(true) - $time, 2) . 's' . PHP_EOL;
  77. }
  78. //打包PDF
  79. $successArr = array();
  80. if ($pdfPathArr) {
  81. $examName = $examInfo['name'];
  82. $filenamePath = dirname(dirname(dirname(__FILE__))) . '/upload/tmpDir/academicr_batch/' . $examGroupId . "/" . $tableId;
  83. if (!is_dir($filenamePath)) {
  84. if (!mkdir($filenamePath, 0777, true)) {
  85. $bool = $this->updateStatus($tableId, 3,'创建压缩文件目录失败: ' . $filenamePath);
  86. }else{
  87. exec('chown -R www:www '.$filenamePath);
  88. }
  89. }
  90. $filename = $filenamePath ."/".$examGroupId.".zip";
  91. // file_put_contents($filename, '');
  92. $successArr = $this->zipPdf($pdfPathArr, $filename, $examName, $classNameArr);
  93. }
  94. //全部成功更新状态
  95. if ($successArr && count($successArr) == array_sum($successArr)) {
  96. //上传qcloud文件
  97. $filename = $this->characet($filename);
  98. $ucloud = new Qcloud();
  99. $filename = iconv("UTF-8","GBK//IGNORE",$filename);
  100. $examName = $this->characet($examName);
  101. $putRs = $ucloud->putFile('zsyas2/academicr_batch/'.$examGroupId.'/'.$tableId.'/'.$examName.'.zip',$filename);
  102. if(isset($putRs['status']) && $putRs['status'] == 1){
  103. $url = $putRs['url'];
  104. $url = str_replace("%2F","/",$url);
  105. $bool = $this->updateStatus($tableId, 2,'',$url);
  106. $this->showMsg(1, 'zip文件上传Ucloud成功!,地址:'.$url);
  107. }else{
  108. $msg = 'zip文件上传Ucloud失败!!!,错误信息:' . $putRs['msg'];
  109. $bool = $this->updateStatus($tableId, 3,$msg);
  110. }
  111. @unlink($filename);
  112. }else{
  113. $bool = $this->updateStatus($tableId, 3,'生成zip文件失败');
  114. }
  115. }
  116. //关闭数据库
  117. if ($this->schConnObj) {
  118. $this->getSchConnObj()->close();
  119. }
  120. echo '下一个学校' . PHP_EOL;
  121. }
  122. echo 'End.' . PHP_EOL;
  123. }
  124. public function getDbConnection($databaseHost,$databaseName,$databaseUser,$databasePassword)
  125. {
  126. if($databaseHost && $databaseName && $databaseUser && $databasePassword){
  127. $myDbDsn = 'mysql:host=' . $databaseHost . ';dbname=' . $databaseName;
  128. $myConnection = new CDbConnection($myDbDsn, $databaseUser, $databasePassword);
  129. $myConnection->emulatePrepare = true;
  130. $myConnection->enableProfiling = true;
  131. $myConnection->enableParamLogging = true;
  132. $myDbDsn = null;
  133. return $myConnection;
  134. }else{
  135. return null;
  136. }
  137. }
  138. /**
  139. * 获取学校数据库
  140. * @param $schoolIds
  141. * @return array
  142. */
  143. protected function getSchoolDatabases($schoolIds)
  144. {
  145. $schoolDatabases = array();
  146. $sql = "select school_id,database_host,database_user,database_password,database_name,group_id from `database` where school_id in (" . implode(',', $schoolIds) . ")";
  147. $rs = $this->getBusConn()->createCommand($sql)->queryAll();
  148. if ($rs) {
  149. foreach ($rs as $value) {
  150. $schoolDatabases[$value['school_id']] = $value;
  151. }
  152. }
  153. return $schoolDatabases;
  154. }
  155. /**
  156. * 业务数据库对象
  157. * @return CDbConnection|null
  158. */
  159. protected function getBusConn()
  160. {
  161. $time = time();
  162. if ($this->busConnObj) {
  163. if ($time - $this->busDbTime > $this->dbTimeout) {
  164. echo '关闭超时业务数据库重新连接' . PHP_EOL;
  165. }else{
  166. return $this->busConnObj;
  167. }
  168. }
  169. $dbParams = Yii::app()->params["default_server"];
  170. $busConnObj = $this->getDbConnection($dbParams['addr'], Yii::app()->params["default_db"]['name'], $dbParams['username'], $dbParams['password']);
  171. $this->busConnObj = $busConnObj;
  172. $this->busDbTime = $time;
  173. return $busConnObj;
  174. }
  175. /**
  176. * 学校数据库对象
  177. * @return mixed
  178. */
  179. public function getSchConnObj()
  180. {
  181. $time = time();
  182. if ($this->schConnObj) {
  183. if ($time - $this->schDbTime > $this->dbTimeout) {
  184. echo '关闭超时学校数据库重新连接' . PHP_EOL;
  185. }else{
  186. return $this->schConnObj;
  187. }
  188. }
  189. $databaseInfo = $this->databaseInfo;
  190. $schConnObj = $this->getDbConnection($databaseInfo['database_host'], $databaseInfo['database_name'], $databaseInfo['database_user'], $databaseInfo['database_password']);
  191. $this->schConnObj = $schConnObj;
  192. $this->schDbTime = $time;
  193. return $schConnObj;
  194. }
  195. /**
  196. * 查询需要处理的考试
  197. * @param $examGroupId
  198. * @param $classStr
  199. * @return array
  200. */
  201. protected function getNeedExamIds($examGroupId, $classStr)
  202. {
  203. $examInfoArr = array();
  204. $rs = array();
  205. $sql = "SELECT exam_id,class_id,`name` FROM exam WHERE exam_group_id = '{$examGroupId}' AND class_id IN ({$classStr}) AND `status` = 1";
  206. $result = $this->getSchConnObj()->createCommand($sql)->queryAll();
  207. if (!$result) {
  208. return $examInfoArr;
  209. }
  210. foreach ($result as $value) {
  211. $examInfoArr[$value['exam_id']] = $value;
  212. }
  213. unset($result);
  214. if ($examInfoArr) {
  215. $sql = "SELECT exam_id FROM paper WHERE exam_id in (" . implode(',', array_keys($examInfoArr)) . ") and is_labelled = 1";
  216. $result = $this->getSchConnObj()->createCommand($sql)->queryAll();
  217. if ($result) {
  218. foreach ($result as $value) {
  219. $rs[$value['exam_id']] = isset($examInfoArr[$value['exam_id']])?$examInfoArr[$value['exam_id']]:0;
  220. }
  221. }
  222. }
  223. unset($examInfoArr);
  224. return $rs;
  225. }
  226. /**
  227. * 需要处理的学校考试
  228. * @return array|CDbDataReader
  229. */
  230. protected function getNeedSchoolExam()
  231. {
  232. $schoolRelExam = array();
  233. $time = time();
  234. //获取要生成教师讲案的数据
  235. $sql = "select id,school_id,exam_group_id,class_ids,class_names from download_table_setting where download_type = 3 and status = 1 and error_msg = '' and subject_id = 12 and is_labelled>0 ";
  236. $result = $this->getBusConn()->createCommand($sql)->queryAll();
  237. //超过20分钟默认生成失败
  238. $sql = "update download_table_setting set status = 3,error_msg ='系统错误,建议单个生成' where status = 4 and error_msg = '' and update_time <" . ($time - 1200);
  239. $this->getBusConn()->createCommand($sql)->execute();
  240. if ($result) {
  241. foreach ($result as $value) {
  242. $schoolId = $value['school_id'];
  243. if (!isset($schoolRelExam[$schoolId])) {
  244. $schoolRelExam[$schoolId] = array();
  245. }
  246. $schoolRelExam[$schoolId][$value['exam_group_id']] = array(
  247. 'class_ids' => $value['class_ids'],
  248. 'class_names' => $value['class_names'],
  249. 'id' => $value['id'],
  250. );
  251. }
  252. }
  253. return $schoolRelExam;
  254. }
  255. /**
  256. * 更新生成状态 状态:1等待生成中,2-已生成 , 3-生成失败 4-生成中
  257. * @param $tableId
  258. * @param $status
  259. * @param string $errorMsg
  260. * @param string $zipUrl
  261. * @return int
  262. */
  263. protected function updateStatus($tableId, $status,$errorMsg = '',$zipUrl = '')
  264. {
  265. $time = time();
  266. $sql = "update download_table_setting set update_time = {$time},`status` = {$status}";
  267. if ($errorMsg) {
  268. $errorMsg = addslashes($errorMsg);
  269. $sql .= ",`error_msg` = '{$errorMsg}'";
  270. $this->showMsg(0, $errorMsg);
  271. }
  272. if ($zipUrl) {
  273. $sql .= ",`zip_url` = '{$zipUrl}'";
  274. }
  275. $sql .= " where id = {$tableId}";
  276. $bool = $this->getBusConn()->createCommand($sql)->execute();
  277. if ($bool === false) {
  278. $this->showMsg(0, '更新生成状态' . $status . '失败!!!!');
  279. }
  280. return $bool;
  281. }
  282. /**
  283. * 显示信息
  284. * @param $status
  285. * @param $msg
  286. */
  287. protected function showMsg($status,$msg)
  288. {
  289. echo $msg . PHP_EOL;
  290. }
  291. /**
  292. * client 渲染HTML
  293. * @param $viewName
  294. * @param $data
  295. * @return string
  296. */
  297. public function viewRender($viewName, $data)
  298. {
  299. extract($data, EXTR_PREFIX_SAME,'data');
  300. ob_start();
  301. ob_implicit_flush(0);
  302. $filePath=dirname(dirname(dirname(__FILE__))).'/protected/views/teaching/'.$viewName . '.php';
  303. require($filePath);
  304. return ob_get_clean();
  305. }
  306. /**
  307. * 生成pdf
  308. */
  309. protected function getPdf(&$pdfPathArr,$tableId,$schoolId,$examId,$classId)
  310. {
  311. $teachingPhysicsObj = new TeachingPhysics($this);
  312. $result = $teachingPhysicsObj->getTeachingPdf($schoolId, $examId, 1);
  313. if (isset($result['status']) && $result['status'] == 0) {
  314. $pdfPathArr[$classId] = $result['pdf_path'];
  315. $this->showMsg(1, '教学宝PDF生成成功!地址:'.$result['pdf_url']);
  316. $this->showMsg(1, ',PDF文件路径地址:'.$result['pdf_path']);
  317. $bool = true;
  318. }else{
  319. $errorMsg = isset($result['error']) ? $result['error'] : '生成失败!!';
  320. $this->showMsg(0, $errorMsg);
  321. $bool = $this->updateStatus($tableId, 3, $errorMsg);
  322. }
  323. return $bool;
  324. }
  325. /**
  326. * 打包PDF
  327. * @param $pdfPathArr
  328. * @param $filename
  329. * @param $examName
  330. * @return array
  331. */
  332. protected function zipPdf($pdfPathArr,$filename,$examName,$classNameArr)
  333. {
  334. $successArr = array();
  335. $examName = iconv("UTF-8","GBK//IGNORE",$examName);
  336. //最终生成的文件名(含路径)
  337. $zip = new ZipArchive();
  338. if ($zip->open($filename, ZIPARCHIVE::OVERWRITE)!==TRUE) {
  339. $this->showMsg(0, $examName . 'zip生成失败!');
  340. }else {
  341. foreach ($pdfPathArr as $classId => $val) {
  342. $className = isset($classNameArr[$classId]) ? $classNameArr[$classId] : '';
  343. $pdfname = '-'.$className.'-教师讲案';
  344. $pdfname = iconv("UTF-8", "GBK//IGNORE", $pdfname);
  345. $res = $zip->addFile($val, $examName . $pdfname . '.pdf');
  346. if (!$res) {
  347. $this->showMsg(0, '添加zip文件失败:'.$val);
  348. }
  349. $successArr[] = $res ? 1 : 0;
  350. }
  351. $zip->close();//关闭
  352. foreach ($pdfPathArr as $k => $val) {
  353. @unlink($val);
  354. }
  355. }
  356. return $successArr;
  357. }
  358. /**
  359. * 字符转换
  360. * @param $data
  361. * @return string
  362. */
  363. protected function characet($data){
  364. if( !empty($data) ){
  365. $fileType = mb_detect_encoding($data , array('UTF-8','GBK','LATIN1','BIG5')) ;
  366. if( $fileType != 'UTF-8'){
  367. $data = mb_convert_encoding($data ,'utf-8' , $fileType);
  368. }
  369. }
  370. return $data;
  371. }
  372. /**
  373. * 获取班级名称
  374. * @param $classAndId
  375. * @return array
  376. */
  377. protected function getClassName($classAndId)
  378. {
  379. $classNameArr = array();
  380. $classIds = explode(',',$classAndId['class_ids']);
  381. $classNames = explode(',',$classAndId['class_names']);
  382. foreach ($classIds as $key => $classId) {
  383. $classNameArr[$classId] = isset($classNames[$key]) ? $classNames[$key] : '';
  384. }
  385. return $classNameArr;
  386. }
  387. }