Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Phppresentation Laravel Package

phpoffice/phppresentation

PHPPresentation is a pure PHP library for creating and writing presentation files in OOXML (PowerPoint) and ODF formats, with support for slides, metadata, fonts, and formatting.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and verify the environment first. The library is a pure-PHP composer package, but the writers are only as good as the extensions underneath them:

composer require phpoffice/phppresentation
php -m | grep -Ei 'zip|xml|gd|mbstring'

You need ext-zip (the PPTX/ODP writers build a ZIP package), ext-dom/ext-xmlwriter/ext-xmlreader (all the OOXML serialization), ext-mbstring for text handling, and ext-gd if you will embed images generated at runtime. Missing ext-zip is the single most common "it silently produces nothing / throws at save" failure.

First working file. The API is imperative and object-graph based: a PhpPresentation holds Slide objects, each slide holds Shape objects (rich text, tables, drawings, charts), and shapes hold style objects.

use PhpOffice\PhpPresentation\PhpPresentation;
use PhpOffice\PhpPresentation\IOFactory;
use PhpOffice\PhpPresentation\Style\Alignment;
use PhpOffice\PhpPresentation\Style\Color;

$pres = new PhpPresentation();

// getActiveSlide() returns the auto-created first slide; createSlide() adds more
$slide = $pres->getActiveSlide();

$shape = $slide->createRichTextShape()
    ->setHeight(120)
    ->setWidth(600)
    ->setOffsetX(40)
    ->setOffsetY(40);

$shape->getActiveParagraph()->getAlignment()
    ->setHorizontal(Alignment::HORIZONTAL_CENTER);

$run = $shape->createTextRun('Q3 Revenue Review');
$run->getFont()
    ->setBold(true)
    ->setSize(32)
    ->setColor(new Color(Color::COLOR_DARKBLUE));

IOFactory::createWriter($pres, 'PowerPoint2007')->save(storage_path('app/q3.pptx'));

Where to look in the repo, in order: samples/ (the most complete, runnable documentation this project has — every feature has a numbered sample), then docs/ for readers/writers and recipes, then the Shape/ namespace and IOFactory source when you need to know what actually exists rather than what you hope exists. There is no Laravel service provider; you consume it as a plain library.

Typical first use case: server-generated decks — a "report" endpoint that turns a query result into a PPTX (title slide, a table slide, a chart slide) rather than hand-authored presentations. That is where this library is genuinely useful.

Implementation Patterns

Wrap it in a builder, never call it from a controller. The API is ~50 lines of fluent mutation per slide; keep it behind dedicated classes:

final class DeckBuilder
{
    public function __construct(private PhpPresentation $pres) {}

    public function titleSlide(string $title, string $subtitle): self { /* ... */ return $this; }

    public function tableSlide(string $heading, array $rows): self
    {
        $slide = $this->pres->createSlide();
        // ... heading shape ...
        $table = $slide->createTableShape(count($rows[0]));

        foreach ($rows as $i => $rowData) {
            $row = $table->createRow();
            foreach ($rowData as $c => $value) {
                $row->getCell($c)->createTextRun((string) $value);
            }
        }
        return $this;
    }
}

This also solves the missing "clone slide" feature — there is no cloneSlide(), so a factory method per slide archetype is the idiomatic way to reuse layouts.

Slide sizing is manual and must match your design. Set the canvas once and derive every offset from constants; PhpPresentation defaults to a standard 10×7.5in (4:3) slide. For 16:9 you must change the layout dimensions explicitly, and every hardcoded offset then needs rechecking — put width/height/margin in a config array rather than sprinkling magic numbers.

Charts: Series + plot type, and always set setResizeProportional(false).

use PhpOffice\PhpPresentation\Shape\Chart\Chart;
use PhpOffice\PhpPresentation\Shape\Chart\Series;
use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar;

$series = new Series();
$series->setTitle('Revenue');
foreach ($data as $label => $value) {
    $series->addPoint(new Series\Point($label, $value));
}

$type = new Bar();
$type->addSeries($series);

$chart = $slide->createChartShape();
$chart->setResizeProportional(false)   // do this BEFORE size/offset calls
    ->setWidth(600)->setHeight(360)
    ->setOffsetX(40)->setOffsetY(120);

$chart->getTitle()->setText('Monthly Revenue');
$chart->getLegend()->setPosition(Legend::POSITION_BOTTOM);
$chart->getPlotArea()->setType($type);
$chart->getPlotArea()->getAxisY()->setFormatCode('#,##0');

Images: prefer Shape\Drawing\File over Drawing\Gd. File stores a path and reads bytes at save time, keeping memory flat. Gd wraps a resource and holds the bitmap for the whole request — fine for one logo, dangerous in a loop over 200 product images.

$slide->createDrawingShape()
    ->setPath(storage_path('app/logo.png'))   // file must still exist at save()
    ->setWidth(120)->setHeight(40)
    ->setOffsetX(700)->setOffsetY(30);

Output: build to a temp path, then hand off. Never echo the binary from the writer; write to storage/app/... or tempnam(), then response()->download(...)->deleteFileAfterSend(true). For big decks, do this in a queued job and store the artifact — request-time generation of a 60-slide deck with charts will time out.

Test on the XML, not on the API. Assertions like $this->assertTrue($pres->getSlideCount() === 3) prove nothing; unzip the saved file and grep ppt/slides/slide1.xml for the expected text, table rows, or chart series. That catches the "it saved but PowerPoint says the file is corrupt" class of bug.

Gotchas and Tips

Reading is far weaker than writing. IOFactory::createReader('PowerPoint2007')->load($path) will give you slides and basic shapes, but charts, images, layout/theme inheritance, and much styling do not round-trip cleanly. Do not design a workflow around "open the client's template, tweak two slides, save." If stakeholders must control the look, either rebuild the theme via the API or treat the deck as fully generated. This is the biggest gap between expectations and reality with this package.

Every shape needs explicit geometry. A rich-text shape with no setWidth()/setHeight() is invisible or zero-sized in PowerPoint. Same for tables and drawings. There is no auto-layout, no auto-shrink, and no text-overflow handling — long strings just spill. Size for the worst-case string and test in real PowerPoint and LibreOffice, which differ on overflow and font substitution.

setResizeProportional(false) on charts must come before the geometry calls, or the chart quietly recomputes its own offsets/size and ignores yours. Also: a Series with zero Points produces a chart PowerPoint may flag as unreadable — always guard for empty data sets.

Fonts and colors are objects, not strings. $run->getFont()->setSize(18)->setColor(new Color('FF0000')) — passing a hex string to setColor fails. Default sizes/colors are conservative; set size and color on every run you create, and remember that theme fonts are not exposed, so you are effectively choosing a literal font name.

Feature gaps to plan around: no animations, no slide transitions, no SmartArt, and limited/incomplete speaker-notes support depending on version. If a requirement mentions any of these, the answer is "not with this library" — don't discover it after building the generator.

ODP is a second-class citizen. The ODPresentation writer exists, but coverage is narrower than PPTX (chart types, table styling, some drawing features). If a client genuinely needs .odp, build and smoke-test a parallel output path rather than assuming parity.

Version skew is real. The 0.9 → 1.x line changed namespaces and some method signatures (IOFactory::createWriter argument order, chart/axis accessors). Pin a caret constraint in composer.json, and when a Stack Overflow snippet doesn't compile, check the version in its answer before debugging your own code.

Debugging recipe: when a generated file won't open, unzip -o out.pptx -d /tmp/deck and inspect [Content_Types].xml, ppt/_rels/presentation.xml.rels, and the offending slideN.xml. PowerPoint's "repair" dialog usually points at a shape whose relationship ID has no matching entry — nearly always an image path that didn't exist at save() time or a chart configured without a plot type.

Licensing: the package is LGPL-3.0 (Packagist reports NOASSERTION, which is a metadata artifact, not a permissive license). Using it as a composer dependency in a SaaS is normally fine, but if your legal team has blanket "no copyleft" rules, get this cleared before it ships — and never copy source files into your own tree.

Extension points: subclasses of Shape\AbstractDrawing and custom Reader/Writer implementations are the sanctioned way to add a feature the library lacks (e.g., a house-style chart). That's real work — budget for it rather than assuming a one-line config toggle exists.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource