<?php use DOMDocument; use RecursiveDirectoryIterator; use RecursiveIteratorIterator; use ZipArchive;class PptxXmlModifier {private $tempDir;private $namespaceA = 'http://schemas.openxmlformats.org/drawingml/2006/main';// 1. 解压 PPTX 文件private function unzip($pptxPath){//$this->tempDir在$zip->addFile($filePath, $relativePath);使用中;relativePath 必须是 Zip 内部相对路径,使用 正斜杠 /,否则会导致 PPTX 无法打开。$uniqid_file_path = ROOT_PATH . 'runtime/cache/uniqid/'.'pptx_' . uniqid();$this->tempDir = str_replace('\\', '/',$uniqid_file_path);if (!is_dir($this->tempDir)) {mkdir($this->tempDir, 0777, true); // 递归创建目录 }$zip = new ZipArchive();if ($zip->open($pptxPath) === TRUE) {$zip->extractTo($this->tempDir);$zip->close();return true;}return false;}// 2. 替换文本(保留 Run 样式结构)private function replaceText($replacements){$slidesPath = $this->tempDir . '/ppt/slides';$slideFiles = glob($slidesPath . '/slide*.xml');foreach ($slideFiles as $slideFile) {$dom = new DOMDocument();$dom->preserveWhiteSpace = false;$dom->formatOutput = true;$dom->load($slideFile);// 获取所有 <a:t> 文本节点$textNodes = $dom->getElementsByTagNameNS($this->namespaceA, 't');foreach ($textNodes as $node) {$originalText = $node->nodeValue;foreach ($replacements as $placeholder => $newValue) {if (strpos($originalText, $placeholder) !== false) {// 核心:只修改节点的值,完全不触碰父级 <a:r> 和 <a:rPr> 中的任何样式属性$node->nodeValue = str_replace($placeholder, $newValue, $originalText);}}}$dom->save($slideFile);}}// 3. 替换图片(支持本地路径和 Base64 字符串)private function replaceImage($imageMap){// $imageMap 格式: ['old_image_filename.jpg' => '新的图片数据']$mediaDir = $this->tempDir . '/ppt/media';foreach ($imageMap as $oldName => $newImagepath) {$newImageSource = ROOT_PATH . $newImagepath;// PPT中的目标图片$targetImage = $mediaDir . '/' . $oldName;if (file_exists($targetImage)) {$data = file_get_contents($newImageSource);if ($data) {// 替换图片 file_put_contents($targetImage, $data);}}}}// 4. 重新打包成新的 PPTXprivate function save($outputPath){$zip = new ZipArchive();if ($zip->open($outputPath, ZipArchive::CREATE | ZipArchive::OVERWRITE) !== TRUE) {return false;}$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($this->tempDir),RecursiveIteratorIterator::LEAVES_ONLY);foreach ($files as $file) {if (!$file->isDir()) {$filePath = $file->getRealPath();$relativePath = substr($filePath, strlen($this->tempDir) + 1);$zip->addFile($filePath, $relativePath);}}return $zip->close();}// 清理临时文件private function cleanup(){if (is_dir($this->tempDir)) {$this->rrmdir($this->tempDir);}}private function rrmdir($dir){if (is_dir($dir)) {$objects = scandir($dir);foreach ($objects as $object) {if ($object != "." && $object != "..") {if (is_dir($dir . "/" . $object)) $this->rrmdir($dir . "/" . $object);else unlink($dir . "/" . $object);}}rmdir($dir);}}/*** @param $template 模板* @param $outputPath 输出文件全路径* @param $textReplacements 文本更换内容* @param $imageReplacements 图片更换内容* @return bool*/public function createpptx($template, $outputPath, $textReplacements, $imageReplacements){if ($this->unzip($template)) {// 3. 执行替换$this->replaceText($textReplacements);$this->replaceImage($imageReplacements);// 4. 保存并输出新文件$this->save($outputPath);$this->cleanup();return true;} else {return false;}} }
使用
$template = ROOT_PATH . P_STATIC . DS . 'template.pptx';$file_path = ROOT_PATH . P_STATIC . DS . 'week' . DS . $day;if (!is_dir($file_path)) {mkdir($file_path, 0777, true); // 递归创建目录 }$output = $file_path . DS . $shopid . '.pptx';$textReplacements = ['{{username}}' => $user_data['name'],'{{shopname}}' => $shop_data['shop_name']];$feilds = ['1'=>['image3.png','image4.png','image5.png'], '2'=>'image6.png', '3'=>'image7.png', '4'=>'image8.png', '5'=>'image9.png', '6'=>'image10.png', '7'=>'image11.png', '8'=>'image12.png', '9'=>'image13.png', '10'=>'image18.png', '11'=>'image15.png', '12'=>'image16.png', '13'=>'image17.png', '14'=>'image20.png', '15'=>'image19.png', '16'=>'image21.png', '17'=>'image22.png', '18'=>'image23.png', '19'=>'image24.png', '20'=>'image29.png', '21'=>'image14.png'];$imageReplacements = [];foreach ($feilds as $key=>$feild) {if (is_array($feild)){$pic1_arr = json_decode($picdata['pic'.$key]);foreach ($pic1_arr as $index => $pic1_item) {$imageReplacements[$feild[$index]] = $pic1_item;}}else{$imageReplacements[$feild]=$picdata['pic'.$key];}}$modifier = new PptxXmlModifier();$result = $modifier->createpptx($template, $output, $textReplacements, $imageReplacements);
