Packages: what they carry, where they live, and how to handle them safely
This guide explains the package pages of the administration interface (Setup > Packages): what a package is, where packages are kept, how the list, a package's page, the upload, the install and uninstall steps, the download and the removal work, which packages the installer depends on, what is checked before a package is accepted, and what to do when something does not behave as expected.
It is written for administrators who move classes, content or extensions between installations, and for whoever looks after the packages that new installations are built from. Every page, field and rule below was checked against the code of this repository on 6 October 2026; the files are listed under References.
Guides · Related: Audit trail · Paging in the administration interface · Safe redirects · Extensions
In short
- A package is a directory with a
package.xmland the files it names: content classes, content objects, extensions, settings files, images and documents. A package is installed (its items are created on the site), imported (it is only kept, as a site package is) or exported (written as one.ezpkgfile). - Packages are kept in repositories, the directories of
var/storage/packages/:localfor packages made or imported here, and one directory per vendor (7x,ez-systems, ...). - The setup wizard installs new sites from these packages, and the published packages are built from them. A package the installer takes as a source is marked Installer source everywhere, and removing one needs its own confirmation.
- Setup > Packages (
/package/list) shows every repository with its counts and one card per package, with a search, filters by repository, type and state, a sort and pages. A package's page is read-only until you press a button. - An upload is inspected before anything of it is written: a file that is not a package, too large, or that holds a path outside the package, a link or a device is refused with a reason. An existing package is never overwritten.
- Removing a package deletes its directory; it does not uninstall it. What the package installed stays.
Contents
- 1. Where packages live
- 2. The package list
- 3. A package's page
- 4. Installer sources
- 5. Downloading a package
- 6. Uploading a package
- 7. Installing and uninstalling
- 8. Creating a package
- 9. Removing packages
- 10. Permissions
- 11. From a shell
- 12. Troubleshooting
- References
1. Where packages live
var/storage/packages/ site.ini [FileSettings] StorageDir + package.ini [RepositorySettings] RepositoryDirectory
├── local/ packages made by the creation wizards or uploaded without a vendor
├── 7x/ package.ini [RepositorySettings] Vendor: the setup wizard's repository
│ ├── sevenx_classes/
│ │ ├── package.xml the definition: name, version, type, maintainers, dependencies, install items
│ │ ├── ezcontentclass/ one XML file per class
│ │ └── .cache/ the kernel's parsed copy of package.xml (not part of the package)
│ └── ...
└── ez-systems/A directory of a repository without a package.xml is not a package. The list counts such directories per
repository ("directories without a package definition") but does not show them: they are leftovers of exports or
wizards that ended early. A directory whose package.xml cannot be read is listed in a warning above the list
with its path, instead of breaking the page as it did before.
The repository a package lands in on upload is the one its <vendor> names, turned into a directory name
(eZ systems becomes ez-systems); a package without a vendor goes to local.
2. The package list
Setup > Packages, /package/list (every repository) or /package/list/<repository> (one).
- The figures: packages, installed, not installed, imported only, installer sources, total size and files, and unreadable directories.
- Repositories: one tile per repository with its packages, size, install states, installer sources and leftovers. The setup wizard's repository is marked. A tile opens that repository's list.
- Find packages: a search over name, summary, type, vendor, version, maintainers and required packages (every
word must match), the repository, the type, the state (installed, not installed, imported only, no install
items, installer sources) and the sort (name, last change, size, version, type, repository, install state).
Apply turns the choice into the page address, so it can be bookmarked and the pages keep it:
/package/list/7x/(search)/demo/(type)/contentobject/(sort)/size. Reverse turns the order around. - The cards: name and version, type, install state, Installer source, summary, repository and vendor,
maintainers, the packages it requires (a missing one is marked) and the packages that require it, size and files
(the kernel's
.cacheleft out), the last change (the newest file of its directory) and when it was packaged. View opens its page, Download its.ezpkg. - Per page and the pages. The sizes on offer are
admininterface.ini [PaginationSettings] ItemsPerPageList_package_list(10, 25, 50, 100 when not set); your choice is kept as a preference. Without a choice the list usesItemsPerPage[package/list](25). See paging. - Remove selected, Import new package and Create new package, each greyed out when your role does not allow it.
Before 6.0.15 the list showed only the local repository unless another was chosen, so the installer's own
packages were out of sight; the pager lost the repository; and the removal title read "Remove section?".
3. A package's page
/package/view/full/<name> or, for a package outside local, /package/view/full/<name>/<repository>. Nothing on
this page changes anything until a button is pressed.
- The title row: name, version, type, install state, Installer source.
- The actions: Compare (the package's content against the site,
package/compare), Install or Reinstall, Download, Uninstall, Remove. Each is shown only when your role allows it and the package can do it; when there is nothing to install the page says why. - Details: repository and vendor, state, license, maintainers, documents, released, packaged (time and host), the Exponential version it was made for, what it requires and what requires it, size and last change, and its description.
- What it carries: its content classes, content (install items and object files), extensions, settings files, other install items, and a table of its files by kind with their sizes.
- Changelog, then Package contents: every file, filtered by kind and searched by path, paged, each viewable
(the first megabyte, XML pretty-printed, a content object summarised) and downloadable. A JSON document is listed
by its kind (Package definition, Content object, Content class) and shown as JSON or as the XML it mirrors, an XML
document as JSON too; long lines wrap, with a No wrap switch. PNG, JPEG, GIF and WebP images are shown inline,
SVG only as text, any other binary as a card with its type, size, SHA-256 and whether it matches
package.json. The package's documents (its license) open here as well. - Validate: checks the package as an upload is checked (below) and shows what was checked, or every problem.
An address that names a view mode without a template (/package/view/nosuchmode/...), a package name with a path
in it (.., a slash) or a repository the storage does not have is answered with "not found".
4. Installer sources
A package is an installer source when at least one of these holds:
| Reason shown | Rule |
|---|---|
| In the setup wizard's repository | It is in package.ini [RepositorySettings] Vendor (7x); the published packages are built from this repository |
| A site package the setup wizard offers | Its type is site; the setup wizard lists every site package |
| Required by another installer source | An installer source requires it (<require type="ezpackage">), directly or through others |
On the demonstration server this marks sevenx_classes, sevenx_multisite and sevenx_multisite_democontent. The card has a blue
edge, the package's page says why, and a removal of one needs the box "I understand that ... installer source(s)
will be deleted" ticked as well.
5. Downloading a package
Download (the list and a package's page) is GET /package/export/<name>[/<repository>]; the older Export to
file button (ExportButton) still posts to the package's page and does the same. The package is written as a
gzip compressed tar (<name>-<version>.ezpkg) into your own export directory
(var/site/cache/packages/export<user id>/, the cache directory of site.ini [FileSettings] VarDir), sent and removed again. The package itself is only read.
JSON (a card) and Download as JSON (a package's page) send the same package in the JSON format
(package.json, <name>-<version>.json.ezpkg); Download there is the classic format. The view parameter is
(format)/json or (format)/xml. The package's page shows the format it is stored in. Both formats upload and
install the same way; see the JSON package format.
The file is sent in pieces of 256 KiB, never read whole, after every output buffer of the page is closed. A
Range header (bytes=a-b, bytes=a-, bytes=-n) gets 206 Partial Content, a range beyond the end
416. Under Exponential Velocity the engine collects a persistent worker's answer before it sends it, so a very
large package costs that much memory there for the moment of the download; the download is byte for byte the same
on both servers. The request ends outside any try/catch, so Velocity's way of ending it cannot append the page
to the file.
Files out of a package (Download in the contents) come from /package/viewfile/<name>/<index>[/<repository>] the
same way; an image is shown inline, everything else is offered as a download with nosniff and a sandboxing
Content-Security-Policy.
6. Uploading a package
Import new package on the list opens /package/upload. Choose an .ezpkg, .tar.gz or .tgz file and
press Import package. Before anything is written, the archive is inspected:
- its name ends in an allowed suffix and the file starts with the gzip signature (or is a plain tar archive);
- it is at most
MaxArchiveSizebytes and has at mostMaxEntriesentries that unpack to at mostMaxUnpackedSizebytes; - its tar headers can be read: the V7 archives of eZ Publish 3.x, the ustar and GNU archives of 4.x and 5.x and of
GNU tar, and PAX archives (bsdtar on macOS, GNU tar
--format=posix) all import; - every entry has a relative path: no
.., no absolute path, no back slash, no control character. A hard or symbolic link to a file of the package is imported as a copy of it; a link out of the package, to a directory or to nothing, a device and a fifo are passed over with a notice (listed among the validation warnings), and the rest of the package is imported; - it has a
package.xmlat its top that is well formed, has<package>as its root and no document type, names a valid package (letters of either case, digits,_and-, not starting with-) and has its version and packaging information, and its vendor gives a repository name; - no package of that name exists in any repository.
The page names the first rule that failed. Then the package itself is validated: each document well formed, the
JSON documents of a JSON package against its schema, and the checksums of its
package.json. A package that fails is refused with the list of what failed. When all hold, the package is
extracted into its repository; a package with install items opens its install step next, any other its page, and
both show the validation result until the next action on the package. Extracted files get mode 0644 and
directories 0755, whatever the archive says.
The limits, with their defaults:
# settings/override/package.ini.append.php
[UploadSettings]
MaxArchiveSize=268435456
MaxUnpackedSize=2147483648
MaxEntries=50000
AllowedSuffixes[]
AllowedSuffixes[]=ezpkg
AllowedSuffixes[]=tar.gz
AllowedSuffixes[]=tgzPHP's own upload_max_filesize and post_max_size apply first; the page shows the server's limit.
The archive check also runs inside eZPackage::import(), so the setup wizard's upload and ezpm import refuse the
same archives.
7. Installing and uninstalling
Install on a package's page opens /package/install/<name>: the list of what will be installed, with
Install package and Skip installation. A package that is installed already says that installing again
repeats every item. Each item is installed in turn; an item may ask how to handle a conflict (a class that exists,
for instance) with its own step.
The page also shows what the install meets here: every content object of the package looked up by its remote ID (new, existing, a conflict, or without its class). Install as drafts writes the content objects as drafts instead: nothing is published, an existing object gets a new draft (or is left alone), classes, settings and design files are not installed, and the result page links every draft for review. See install as drafts.
The report lists every object with what the install does with it and where its main location goes (at the top, below a node here, below a node of the package, or below a missing one), with the counts of each.
Install in the background runs the same install as a content job (packageinstall)
as you, with the choices you made; the page suggests it for a package with more objects than
[ContentJobSettings] SynchronousLimit. The package's page then shows the progress object by object and lists the
drafts when it is done. An extension can react to every install as drafts through the event
package/install/drafts (the JSON package format).
Uninstall opens /package/uninstall/<name>: what uninstalling removes from the site, content included, with
Uninstall package and Skip uninstallation. Uninstalling cannot be undone.
Both need package/install for the package's type (they asked for the policy for any type before).
8. Creating a package
Create new package opens /package/create: one tile per wizard your role may use (content object export,
content class export, extension export, site style). The wizard asks for the parts, then name, summary, version,
license and maintainer, and the format the package is kept in (Classic XML or JSON), and writes the package into
local. Nothing on the site changes. Each step shows where you are in the wizard, marks errors at their fields, and the
last step reviews the whole package before Create package writes it: see The package
wizard.
9. Removing packages
- Tick the packages on the list (or press Remove on a package's page) and press Remove selected.
- The confirmation lists what goes: per package its directory, size and files, whether it is installed, which packages require it, and why it is an installer source. Above the list: how many packages, files and bytes, installed packages, installer sources and packages required by packages that stay.
- Anything selected that cannot be removed is listed with its reason: not a package name, no such package, a name in more than one repository, not allowed for its type, or a directory containing links.
- Press Remove n package(s); with installer sources among them, tick the box first.
The directory is deleted with everything in it. The package is not uninstalled: classes, content and files it
installed stay; only the record that it is installed goes, so it can no longer be uninstalled from here. Download a
package first to keep a copy. Each removal is recorded in the audit trail as system.package.remove with the
package's name, version, repository, files, bytes, whether it was installed and whether it was an installer source.
Only what the confirmation page offered can be removed: a ConfirmRemovePackageButton posted without it removes
nothing. A package whose directory contains a symbolic link is never offered: the kernel's recursive delete
follows a link to a directory and would empty its target.
10. Permissions
| Action | Policy | Limited by |
|---|---|---|
| See the list | package/list | |
| A package's page, its files, Compare | package/read | Type |
| Download | package/export | Type |
| Upload | package/import | |
| Install, Reinstall, Uninstall | package/install | Type |
| Remove | package/remove | Type |
| Create | package/create | Type, creator, role |
Every form carries the form token; a post without it is refused with 403.
11. From a shell
php ezpm.php list --allow-root-user # the packages of the repositories
php ezpm.php export sevenx_classes -d var/tmp --allow-root-user # write an .ezpkg (only reads the package)
php ezpm.php import var/tmp/x.ezpkg --allow-root-user # the same archive checks as the upload page
php ezpm.php help --allow-root-user # every command12. Troubleshooting
| You see | Why | What to do |
|---|---|---|
| A package is missing from the list | Its package.xml cannot be read, or names another package than its directory | The warning above the list names the directory; fix or replace package.xml |
| "N directories without a package definition" | Leftovers of exports or wizards that ended early | Look at them on the server; nothing reads them |
| Upload: "points outside the package" or "is a link or a device" | The archive was made with links or unsafe paths | Make the archive again from the package directory (ezpm export) |
| Upload: "not a well formed package definition" | package.xml is broken | Check it with xmllint --noout package.xml |
| Upload: "already exists" | A package of that name is in some repository | Remove the old one first, or give the new one another name |
| Download answers "not found" | Exporting failed (the debug output says why) | Check that var/site/cache/packages/ (the cache directory) is writable for the web server and Velocity |
| Remove is greyed out for one package | Its directory contains a link | Remove it on the server after checking where the link points |
References
- Views:
kernel/private/classes/views/package/list.php,view.php,export.php,viewfile.php,upload.php,install.php,uninstall.php; module definitionkernel/package/module.php. - Classes:
eZPackageCatalog(repositories, cards, installer sources, search, sort, contents),eZPackageRemovalPlan,eZPackageUploadInspector,eZPackageDownload,eZPackageRequestGuard,eZPackageFileBrowser,eZPackage(all inkernel/classes/). - Templates:
design/admin/templates/package/anddesign/admin4/templates/package/(exp_style.tpl,list.tpl,confirmremove.tpl,view/full.tpl,upload.tpl,install.tpl,uninstall.tpl,create.tpl). - Tests (no database):
tests/tests/kernel/classes/packages/eZPackageCatalogTest.php,eZPackageUploadInspectorTest.php,eZPackageRequestGuardTest.php,eZPackageDownloadTest.php. - Changelog 6.0.15
Related pages
Become an Exponential Partner
Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.