1,文件上传,这个基础了。另外,文件上传的大小,在php.ini可以设置,但是最后决定上传的大小的,是postmax的设置。
2,获取文件,然后将其读取,若文件太大,就将其分割
3,正则识别章节标题内容,然后记录下来
4,将文件按行读取匹配章节标题,记录行数
5,按章节标题行数-1,分割文件
6,记录,入库,这样就能完整的得到整本小说的目录,和章节内容
/*** 原生上传文件* 根据上传的文件名判断文件在该路径是否已经上传*/public static function phpUpload($type,$path){//防止乱码header("Content-type: text/html; charset=utf-8");$file=$type;if ($_FILES[$file]['error']>0){ //file 是post上字段名return "Error:".$_FILES[$file]['error'];}//上传文件信息$data=['fileName'=>$fileNmae=$_FILES[$file]['name'],"type"=>$type=$_FILES[$file]['type'],'size'=>$size=($_FILES[$file]['size']/1024)."kb",'tmp_name'=>$tmp_name=$_FILES[$file]['tmp_name'],];$filepath=$path.DS.$fileNmae; //文件路径,包含文件名$fileNmae=iconv('utf-8','gb2312',$fileNmae);if (self::fileIsHas($filepath))return null; //判断文件是否已经上传if (!self::fileIsHas($path)) self::createdir($path); //没有该文件夹则创建move_uploaded_file($tmp_name,$filepath);return $filepath;}
/*** 分段器* 默认每2m分段一次* filePath 文件路径* callback 回调函数,分割完文件,可以在回调函数中进行接下来步骤处理* blockSize 分割文件大小,默认是2m*/public static function sectionalizer($filePath,$callback,$blockSize=10485760 / 5){if (!is_callable($callback))return false;$size=filesize($filePath); //整体大小while ($size>0){$residue=bcsub($size,$blockSize,0);$callbackSize=$residue>0?$residue:$size;$data=$callback($callbackSize); //回调函数,分段期间做的事$size=$residue;}return $data;}
/*** 获取整字符内容* @param $path*/public static function pregChapters(string $path,string $pattern,int $size){$file=fopen($path,'rb')or die("unable open the file");$content=fread($file,$size);fclose($file);//$pattern="/chapter[\s][A-Z]/i";preg_match_all($pattern,$content,$result,PREG_PATTERN_ORDER);return $result;}
/*** 返回章节对应的行数* @param $path* @param array $chapterName* @return array*/public static function ChaptersLine($path,array $chapterName){$fp=fopen($path,"rb");$lines=[]; //每一行$num=[]; //每一章节对应的行数while (!feof($fp)){$lines[]=fgets($fp);}$i=0; //章节下标$chapterName=array_flip($chapterName); //翻转数组,redis思想foreach ($lines as $k=> $line){if (empty($line))continue;if (isset($chapterName[trim($line)])){ //存在该下标,存在$i++;$num[]=['chapter_name'=>$lines[$k],'line_num'=>$k,'chapter_num'=>$i];}}fclose($fp);return $num;}
/*** 分割章节* @param $path* @param $chapterNum* @param $novels_id* @throws \think\exception\DbException*/public static function splitByChapter($path,$chapterNum,$novels_id){$chapterPath=dirname($path).DS;$novels=Novels::get($novels_id);$chapterData=['novels_id'=>$novels_id,'title'=>$novels->title,'created_at'=>time(),];$i=0;$word_count=0;foreach ($chapterNum as $k =>$v){$endLine=$v['line_num']-1;$content=self::getLine($path,$i,$endLine); //获取行,内容self::ChapterTxt($chapterPath.$v['chapter_num'].".txt",$content); //生成章节文本$chapterData['word_count']=help::wordCount($content); //字数统计$chapterData['num']=$v['chapter_num'];$chapterData['path']=NOVELS_PATH_MYSQL.$novels->title.DS.$v['chapter_num'].".txt"; //章节目录路径,重组$chapter=Chapter::create($chapterData); //入章节表$chapterManagerData=['chapter_num'=>$v['chapter_num'],'title'=>$chapterData['title'],'words_num'=>$chapterData['word_count'],'createtime'=>time(),];ChapterManage::create($chapterManagerData); //后台章节列表页HandleRedis::getInstance()->chapterCache($novels_id.":".$chapter->getLastInsID(),json_encode($chapterData)); //种缓存$word_count+=$chapterData['word_count'];$i=$endLine;}return $word_count;}
/*** 根据行数分割文件* &#64;param $fileName* &#64;param $start* &#64;param $limit* &#64;return string*/public static function getLine($fileName,$start,$limit){$f&#61; new \SplFileObject($fileName,&#39;r&#39;);$f->seek($start); //文件指针指向行数$ret&#61;&#39;&#39;;for ($i&#61;0;$i<$limit;$i&#43;&#43;){$ret.&#61;$f->current(); //内容$f->next(); //下一行}return $ret;}
/*** 生成章节文件* &#64;param $chapterPath* &#64;param $content* &#64;return false|mixed*/public static function ChapterTxt($chapterPath,$content){if (help::fileIsHas($chapterPath))return false;$fp&#61;fopen($chapterPath,&#39;wb&#39;)or die(__("can&#39;t open this file :".$chapterPath));fwrite($fp,$content);fclose($fp);return $chapterPath;}
整体调用总函数
/*** 上传整本小说&#xff0c;分割章节&#xff0c;然后更新库* &#64;param string $path* &#64;param array $novels_id* &#64;param string $patten* &#64;throws \think\exception\DbException*/public static function wholeNovelsChapters(string $path,int $novels_id,string $patten&#61;"/chapter[\s][A-Z]&#43;\./i"){/*$dir&#61;novels_opeate::sectionalizer($path,function($size)use($path,$patten,$dir){$dir[]&#61;novels_opeate::pregChapters($path,$patten,$size); //分段将目录导入dir数组内return $dir;});*/$dir&#61;novels_opeate::pregChapters($path,$patten,filesize($path))[0]; //获取章节目录$chaptersNum&#61;novels_opeate::ChaptersLine($path,$dir); //获取章节目录所在的行数$word_count&#61;novels_opeate::splitByChapter($path,$chaptersNum,$novels_id); //分割整本书&#xff0c;生成章节txt文件,入库$chaptersNum&#61;array_sum($chaptersNum);novels_model::where(&#39;id&#39;,$novels_id) //更新小说表->update([&#39;path&#39;&#61;>dirname($path).DS,&#39;chapter_count&#39;&#61;>$chaptersNum, //小说章节总数&#39;word_count&#39;&#61;>$word_count,]);unlink($path); //删除原本}