PDF dosyalarını PHP ile birleştirme [kapalı]


83

Benim konseptim - bir web sitesinde 10 pdf dosyası var. Kullanıcı bazı pdf dosyalarını seçebilir ve ardından seçilen sayfaları içeren tek bir pdf dosyası oluşturmak için birleştirmeyi seçebilir. Bunu php ile nasıl yapabilirim?


İlgili soru (cevaplandı btw): stackoverflow.com/questions/2713701/…
Fran Verona

3
@Webnet aslında,% 64 tamam. % 0-25 = başarısız derdim, ama sanırım öznelleştiği yer burası
Sean Patrick Floyd

Bir komut satırı aracı kullanabilir misiniz?
Pekka

Zend Framework kullanabilir misiniz? stackoverflow.com/questions/4254218/…
Pekka

"Pdftk-112-1i386.rpm" dosyasını nerede bulabilirim ve sunucuya nasıl kurabilirim?
İmrul.

Yanıtlar:


28

Bunu daha önce yaptım. Fpdf ile oluşturduğum bir pdf'im vardı ve ona değişken miktarda PDF eklemem gerekiyordu.

Bu yüzden zaten bir fpdf nesnem ve sayfa kurulumum vardı (http://www.fpdf.org/) Ve dosyaları içe aktarmak için fpdi kullandım (http://www.setasign.de/products/pdf-php-solutions/ fpdi /) FDPI, PDF sınıfı genişletilerek eklenir:

class PDF extends FPDI
{

} 



    $pdffile = "Filename.pdf";
    $pagecount = $pdf->setSourceFile($pdffile);  
    for($i=0; $i<$pagecount; $i++){
        $pdf->AddPage();  
        $tplidx = $pdf->importPage($i+1, '/MediaBox');
        $pdf->useTemplate($tplidx, 10, 10, 200); 
    }

Bu, temelde her pdf'yi diğer pdf'nize koymak için bir görüntü haline getirir. İhtiyacım olan şey için inanılmaz derecede iyi çalıştı.


Kodunuzu anlayamıyorum. lütfen biraz daha ayrıntı açıklar mısınız? Ayrıca fpdf kılavuzunda "setSourceFile" ve "importPage" işlevlerini bulamadım.
İmrul.

Geri döndüm ve çözümüme biraz daha detaylı baktım. Umarım bu daha yararlı olur. Bu sabah bunu yazdığımda fdpi bölümünü tamamen unuttum, yazdığım oldukça karmaşık bir PDF oluşturucunun küçük bir parçası.
Christa

7
@Christa FPDI'nin yalnızca belirli PDF dosyalarını ayrıştıracağına dikkat edin. FPDI'nin v 1.4'ün üzerindeki PDF dosyalarını ayrıştırmayacağı bir sorunla karşılaşıyorum ve FPDI,> v1.4 ... yar ....
n0nag0n

$ İ = 0 ve $ i <= $ pagecount yapmanın daha iyi olduğunu düşünmüyor musunuz? Sanırım okumayı daha iyi hale getiriyor. Harika bir örnek btw, gerçekten bana yardımcı oldu
Nebulosar

126

Aşağıda php PDF birleştirme komutu verilmiştir.

$fileArray= array("name1.pdf","name2.pdf","name3.pdf","name4.pdf");

$datadir = "save_path/";
$outputName = $datadir."merged.pdf";

$cmd = "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=$outputName ";
//Add each pdf file to the end of the command
foreach($fileArray as $file) {
    $cmd .= $file." ";
}
$result = shell_exec($cmd);

Bağlantıyı bulduğum yerden unuttum ama iyi çalışıyor.

Not: Bunun çalışması için gs (Linux'ta ve muhtemelen Mac'te) veya Ghostscript (Windows'ta) kurulu olmalıdır.


4
Benim için sorunsuz ve harici kitaplıkları FPDI veya diğerleri olarak kurmadan çalıştı.
Memochipan

4
Bu çözüm benim için en iyisi oldu. Ghostscript'i sunucuma kurmak çok kolaydı. Sadece "harika kurulum ghostscript" idi. Senaryonuz mükemmel çalıştı
Theo Kouzelis

1
Boş bir pdf sayfası alıyorum :(
itsazzad

2
Ghostscript'in kurulu olması gerekir, aksi takdirde sessizce başarısız olur.
Pascal Klein

2
Gerçekte ne yaptığını açıklamalısın. Aslında bu, görevi yerine getirmenin gerçekten bir php yolu değildir, php'de yalnızca verileri hazırlarsınız ve ardından asıl görevi yerine getiren bir kabuk betiğini çalıştırırsınız. Ayrıca cevabınıza, bunun çalışması için gs (linux ve muhtemelen Mac üzerinde) veya Ghostscript (Windows üzerinde) yüklenmesini de eklemelisiniz .. Yine de bu çözümü çok beğeniyorum, çünkü gs varsayılan olarak Ubuntu'ya dahildir. , yüklemek zorunda değildim.
Vulgo Alias

39

i önermek PDFMerger dan github.com kadar kolay olduğu gibi, ::

include 'PDFMerger.php';

$pdf = new PDFMerger;

$pdf->addPDF('samplepdfs/one.pdf', '1, 3, 4')
    ->addPDF('samplepdfs/two.pdf', '1-2')
    ->addPDF('samplepdfs/three.pdf', 'all')
    ->merge('file', 'samplepdfs/TEST2.pdf'); // REPLACE 'file' WITH 'browser', 'download', 'string', or 'file' for output options

3
Bu temelde birisinin @ Christa'nın cevabının (FPDF + FDPI) uygulamasıdır, bu harika :) Teşekkürler!
Nahuel

5
Ayrıca bazı PDF'lerde bazı sıkıştırma türleriyle çalışmaz.
Theo Kouzelis

3
Bunu DOMPDF ile kullanmak ve harika çalışıyor, teşekkürler!
Matthew

1
"FPDF hatası: xref tablosu bulunamıyor" mesajı alıyorum. bunun için herhangi bir çözüm?
Sameeraa4ever

1
Çalışıyor ancak bazen aşağıdaki hatayı gösteriyor ... FPDF hatası: Bu belge (samplepdfs / four.pdf) muhtemelen FPDI ile birlikte gönderilen ücretsiz ayrıştırıcı tarafından desteklenmeyen bir sıkıştırma tekniği kullanmaktadır.
Nikhil

12
$cmd = "gs -q -dNOPAUSE -dBATCH -sDEVICE=pdfwrite -sOutputFile=".$new." ".implode(" ", $files);
shell_exec($cmd);

Chauhan'ın cevabının basitleştirilmiş bir versiyonu


Bu, hostgator centos adanmış sunucusunda benim için iyi çalıştı, bu yüzden ghostscript zaten kurulu olmalı
Mike Volmar

Çok KOLAY olduğu için de doğru cevap olarak işaretlenmelidir. FPDF ve FPDI ile mücadele eden saatler doğru yüklenmiyor. Hayatımı kurtardın. Sunucuya "imagemagick" i (debian / ubuntu: apt install imagemagick) kurmanız yeterlidir ve sorun değil. Şerefe!
Florian Doyen

9

Hem kabul edilen cevap hem de FDPI ana sayfası başarısız veya eksik örnekler veriyor gibi görünüyor. İşte çalışan ve uygulaması kolay olan benim. Beklendiği gibi, fpdf ve fpdi kitaplıklarını gerektirir:

require('fpdf.php');
require('fpdi.php');

$files = ['doc1.pdf', 'doc2.pdf', 'doc3.pdf'];

$pdf = new FPDI();

// iterate over array of files and merge
foreach ($files as $file) {
    $pageCount = $pdf->setSourceFile($file);
    for ($i = 0; $i < $pageCount; $i++) {
        $tpl = $pdf->importPage($i + 1, '/MediaBox');
        $pdf->addPage();
        $pdf->useTemplate($tpl);
    }
}

// output the pdf as a file (http://www.fpdf.org/en/doc/output.htm)
$pdf->Output('F','merged.pdf');

Merhaba @billynoah Bunu beğendim ama manzara üzerinde çalışmıyor ve sadece 1. sayfaları birleştiriyor gibi görünüyor.
Geraldo Isaaks

2
@GeraldoIsaaks - Daha sonra kendi uygulamama çok sayfalı belgeler için destek ekledim. Cevabı güncelledim. Manzara sorunları hakkında emin değilim - bununla karşılaşmadım.
billynoah

FPDI'nin ilk günlerinden beri mevcut olan bu sınavda ne var ?
Jan Slabon

@Setasign - Bunu hiç görmedim ama paylaştığın için teşekkürler.
billynoah

@billynoah SO'daki açık ve güncellenmiş basit kod örneği için teşekkürler. Başlamamı sağladı. Setasign örneğindeki kodun daha fazlasını kullandım ( setasign.com/products/fpdi/demos/concatenate-fake , yukarıdaki yorumda bağlantı kolayca gözden kaçabilir ). AddPage çağrısı içindeki mantıkları, birleştirilmiş sayfalarımın daha iyi görünmesini sağladı. Bunu test etmesem de muhtemelen portre / manzarayı daha iyi işliyor. Ama aramalarla örneği bulamadım ve cevabınızı görene kadar ilgilendiğimi bilmiyordum.
Anne Gunn

5

Yazılımımda da benzer bir sorun yaşadım. Birkaç PDF dosyasını tek bir PDF dosyasında birleştirmek ve bir dış hizmete göndermek istedik. Gösterildiği gibi FPDI çözümü kullanıyorum Christa 'ın çözümü.

Ancak, kullandığımız girdi PDF'leri 1.7'den yüksek sürümde olabilir. FPDI ticari eklentisini değerlendirmeye karar verdik. Ancak, ofis fotokopi makinemiz tarafından taranan bazı belgelerin, ticari FPDI eklentisini çökerten hatalı biçimlendirilmiş dizinlere sahip olduğu ortaya çıktı. Bu yüzden Chauhan'ın cevabında olduğu gibi Ghostscript çözümünü kullanmaya karar verdik .

Ancak çıktı PDF özelliklerinde bazı garip meta veriler elde ettik.

Sonunda PDF'lerin Ghostscript tarafından birleştirilip indirgenmesi için iki çözümü birleştirmeye karar verdik, ancak meta veriler FPDI tarafından belirleniyor. Bazı gelişmiş biçimlendirilmiş pdf'lerle nasıl çalışacağını henüz bilmiyoruz, ancak kullandığımız taramalar için gayet iyi çalışıyor. İşte sınıftan alıntımız:

class MergedPDF extends \FPDI
{
    private $documentsPaths = array();

    public function Render()
    {
        $outputFileName = tempnam(sys_get_temp_dir(), 'merged');

        // merge files and save resulting file as PDF version 1.4 for FPDI compatibility
        $cmd = "/usr/bin/gs -q -dNOPAUSE -dBATCH -dCompatibilityLevel=1.4 -sDEVICE=pdfwrite -sOutputFile=$outputFileName";
        foreach ($this->getDocumentsPaths() as $pdfpath) {
            $cmd .= " $pdfpath ";
        }
        $result = shell_exec($cmd);
        $this->SetCreator('Your Software Name');
        $this->setPrintHeader(false);
        $numPages = $this->setSourceFile($outputFileName);
        for ($i = 1; $i <= $numPages; $i++) {
            $tplIdx = $this->importPage($i);
            $this->AddPage();
            $this->useTemplate($tplIdx);
        }

        unlink($outputFileName);

        $content = $this->Output(null, 'S');

        return $content;
    }

    public function getDocumentsPaths()
    {
        return $this->documentsPaths;
    }

    public function setDocumentsPaths($documentsPaths)
    {
        $this->documentsPaths = $documentsPaths;
    }

    public function addDocumentPath($documentPath)
    {
        $this->documentsPaths[] = $documentPath;
    }
}

Bu sınıfın kullanımı aşağıdaki gibidir:

$pdf = new MergedPDF();
$pdf->setTitle($pdfTitle);
$pdf->addDocumentPath($absolutePath1);
$pdf->addDocumentPath($absolutePath2);
$pdf->addDocumentPath($absolutePath3);
$tempFileName = tempnam(sys_get_temp_dir(), 'merged');
$content = $pdf->Render();
file_put_contents($tempFileName, $content);

Aynı kodu Windows env üzerinde kullandığımı belirtmek isterim. ve program klasörünü "içine koymayı unutmayın, ancak parametreleri koymayın.$cmd = "\"C:\\Program Files\\gs\\gs9.20\\bin\\gswin64c.exe\" -q -dNOPAUSE -dBATCH -dCompatibilityLevel=1.4 -sDEVICE=pdfwrite -sOutputFile=[....your parameters...]" ;
Frédéric Klee

3

Benzer sorunu denedim ve iyi çalışıyor, deneyin. PDF'ler arasındaki farklı yönlendirmeleri işleyebilir.

    // array to hold list of PDF files to be merged
    $files = array("a.pdf", "b.pdf", "c.pdf");
    $pageCount = 0;
    // initiate FPDI
    $pdf = new FPDI();

    // iterate through the files
    foreach ($files AS $file) {
        // get the page count
        $pageCount = $pdf->setSourceFile($file);
        // iterate through all pages
        for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) {
            // import a page
            $templateId = $pdf->importPage($pageNo);
            // get the size of the imported page
            $size = $pdf->getTemplateSize($templateId);

            // create a page (landscape or portrait depending on the imported page size)
            if ($size['w'] > $size['h']) {
                $pdf->AddPage('L', array($size['w'], $size['h']));
            } else {
                $pdf->AddPage('P', array($size['w'], $size['h']));
            }

            // use the imported page
            $pdf->useTemplate($templateId);

            $pdf->SetFont('Helvetica');
            $pdf->SetXY(5, 5);
            $pdf->Write(8, 'Generated by FPDI');
        }
    }

Bu verirUndefined index: w
senty

doğru şekilde yapılandırılmış FPDF'ye sahip olduğunuzdan emin olun
Kevin Chui

benim için parametreler $ size ['w'] ve $ size ['h'] yerine $ size ['width'] ve $ size ['height'] idi
gorillagoat

0

FPDI üzerinde bir soyutlama katmanı oluşturdum (diğer motorları da barındırabilir). Kitaplığa bağlı olarak Symfony2 paketi ve kitaplığın kendisi olarak yayınladım.

Demet

Kütüphane

kullanım:

public function handlePdfChanges(Document $document, array $formRawData)
{
    $oldPath = $document->getUploadRootDir($this->kernel) . $document->getOldPath();
    $newTmpPath = $document->getFile()->getRealPath();

    switch ($formRawData['insertOptions']['insertPosition']) {
        case PdfInsertType::POSITION_BEGINNING:
            // prepend 
            $newPdf = $this->pdfManager->insert($oldPath, $newTmpPath);
            break;
        case PdfInsertType::POSITION_END: 
            // Append
            $newPdf = $this->pdfManager->append($oldPath, $newTmpPath);
            break;
        case PdfInsertType::POSITION_PAGE: 
            // insert at page n: PdfA={p1; p2; p3}, PdfB={pA; pB; pC} 
            // insert(PdfA, PdfB, 2) will render {p1; pA; pB; pC; p2; p3} 
            $newPdf = $this->pdfManager->insert(
                    $oldPath, $newTmpPath, $formRawData['insertOptions']['pageNumber']
                );
            break;
        case PdfInsertType::POSITION_REPLACE: 
            // does nothing. overrides old file.
            return;
            break;
    }
    $pageCount = $newPdf->getPageCount();
    $newPdf->renderFile($mergedPdfPath = "$newTmpPath.merged");
    $document->setFile(new File($mergedPdfPath, true));
    return $pageCount;
}

0

Bu benim için Windows'ta çalıştı

  1. PDFtk'yi https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/ adresinden ücretsiz indirin
  2. klasörü (PDFtk) c:
  3. Aşağıdakileri php kodunuza ekleyin; burada $ file1, ilk PDF dosyasının konumu ve adı, $ file2, ikincinin konumu ve adı ve $ newfile, hedef dosyanın konumu ve adıdır

    $file1 = ' c:\\\www\\\folder1\\\folder2\\\file1.pdf';  
    $file2 = ' c:\\\www\\\folder1\\\folder2\\\file2.pdf';  
    $file3 = ' c:\\\www\\\folder1\\\folder2\\\file3.pdf';   
    
    $command =  'cmd /c C:\\\pdftk\\\bin\\\pdftk.exe '.$file1.$file2.$newfile;
    $result = exec($command);
    

Bunu daha temiz hale getiren bir PHP sarmalayıcısı var. Bkz. Github.com/mikehaertl/php-pdftk
Sean the Bean

Not: PdfTK RHEL 7 veya Cent OS 7 ile çalışmaz
Ray

Benim için sadece şu şekilde çalıştı: $command = "cmd /c C:\\pdftk\\bin\\pdftk.exe {$file1} {$file2} cat output {$new}";Ek cat çıktısına dikkat edin . PDFtk örneklerine
maxpower9000

-1

myokyawhtun'un çözümü benim için en iyi şekilde çalıştı (PHP 5.4 kullanarak)

Yine de bir hata alacaksınız - aşağıdakileri kullanarak çözdüm:

Fpdf_tpl.php'nin 269. satırı - işlev parametrelerini şu şekilde değiştirdi:

function Image($file, $x=null, $y=null, $w=0, $h=0, $type='', $link='',$align='', $resize=false, $dpi=300, $palign='', $ismask=false, $imgmask=false, $border=0) { 

Aynı değişikliği fpdf.php'nin 898. satırında da yaptım.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.