Composer / PHP Guide
Artifact Keeper provides a fully compatible Composer repository for publishing and installing PHP packages.
Endpoint
All Composer operations use the /composer/{repo} endpoint:
http://localhost:8080/composer/my-repoReplace my-repo with your repository name.
Format Key
When configuring Artifact Keeper, use the format key:
composerConfiguration
composer.json Repository Configuration
Add Artifact Keeper as a repository in your project’s composer.json:
{ "repositories": [ { "type": "composer", "url": "http://localhost:8080/composer/my-repo" } ], "require": { "mycompany/my-package": "^1.0" }}Global Composer Configuration
Configure Artifact Keeper globally for all projects:
composer config --global repositories.artifact-keeper composer http://localhost:8080/composer/my-repoView global configuration:
composer config --global --listMultiple Repositories
Use multiple Artifact Keeper repositories:
{ "repositories": [ { "type": "composer", "url": "http://localhost:8080/composer/production" }, { "type": "composer", "url": "http://localhost:8080/composer/development" } ]}Repository Priority
Control repository resolution order:
{ "repositories": [ { "type": "composer", "url": "http://localhost:8080/composer/my-repo" }, { "packagist.org": false } ]}Setting "packagist.org": false disables the default Packagist repository, ensuring all packages come from your private repository.
Authentication
auth.json Configuration
Create or edit auth.json in your project root or Composer home directory (~/.composer/auth.json):
{ "http-basic": { "localhost:8080": { "username": "your-username", "password": "your-password" } }}Bearer Token Authentication
For token-based authentication:
{ "bearer": { "localhost:8080": "your-auth-token" }}Global Authentication
Store credentials globally:
composer config --global http-basic.localhost:8080 your-username your-passwordOr for bearer tokens:
composer config --global bearer.localhost:8080 your-auth-tokenEnvironment Variables
Use environment variables for CI/CD:
export COMPOSER_AUTH='{"http-basic":{"localhost:8080":{"username":"user","password":"pass"}}}'composer installPublishing Packages
Prepare Your Package
Ensure composer.json is properly configured:
{ "name": "mycompany/my-package", "description": "My awesome PHP package", "type": "library", "license": "MIT", "version": "1.0.0", "require": { "php": ">=8.0" }, "autoload": { "psr-4": { "MyCompany\\MyPackage\\": "src/" } }}Create Package Archive
Build a distribution archive:
# Create zip archivezip -r mycompany-my-package-1.0.0.zip . -x "*.git*" "tests/*" "vendor/*"
# Or use tartar -czf mycompany-my-package-1.0.0.tar.gz --exclude='.git' --exclude='tests' --exclude='vendor' .Publish to Repository
Upload the package using the Artifact Keeper API:
curl -X POST \ -F "file=@mycompany-my-package-1.0.0.zip" \ -F "name=mycompany/my-package" \ -F "version=1.0.0" \ -u your-username:your-password \ http://localhost:8080/api/v1/composer/my-repo/packagesAutomated Publishing with Git Tags
Create a script to automatically publish from Git tags:
#!/bin/bashVERSION=$(git describe --tags --abbrev=0)PACKAGE_NAME="mycompany/my-package"ARCHIVE="${PACKAGE_NAME//\//-}-${VERSION}.zip"
# Create archive from git taggit archive --format=zip --prefix="${PACKAGE_NAME//\//-}/" -o "$ARCHIVE" "$VERSION"
# Upload to Artifact Keepercurl -X POST \ -F "file=@$ARCHIVE" \ -F "name=$PACKAGE_NAME" \ -F "version=$VERSION" \ -u "$ARTIFACT_KEEPER_USER:$ARTIFACT_KEEPER_PASSWORD" \ http://localhost:8080/api/v1/composer/my-repo/packages
rm "$ARCHIVE"Installing Packages
Install Package
composer require mycompany/my-packageInstall from composer.json
composer installInstall Specific Version
composer require mycompany/my-package:1.0.0composer require mycompany/my-package:^1.0composer require mycompany/my-package:~1.2.3Install with Development Dependencies
composer install --devInstall without Development Dependencies
composer install --no-devUpdate Packages
# Update all packagescomposer update
# Update specific packagecomposer update mycompany/my-package
# Update to latest minor versioncomposer update mycompany/my-package --with-dependenciesVersion Constraints
Composer supports various version constraint formats:
Exact Version
{ "require": { "mycompany/my-package": "1.0.2" }}Range Operators
{ "require": { "mycompany/my-package": ">=1.0", "mycompany/other-package": ">1.0,<2.0", "mycompany/another-package": ">=1.0,<1.1 || >=1.2" }}Caret Operator (^)
Allows changes that do not modify the leftmost non-zero digit:
{ "require": { "mycompany/my-package": "^1.2.3" }}Equivalent to >=1.2.3,<2.0.0
Tilde Operator (~)
Allows the last digit specified to increment:
{ "require": { "mycompany/my-package": "~1.2.3" }}Equivalent to >=1.2.3,<1.3.0
Wildcard (*)
{ "require": { "mycompany/my-package": "1.2.*" }}Equivalent to >=1.2.0,<1.3.0
Stability Flags
{ "require": { "mycompany/my-package": "1.0.0@beta", "mycompany/other-package": "dev-master" }, "minimum-stability": "stable"}Private Packages / Satis Replacement
Artifact Keeper can completely replace Satis for hosting private Composer packages.
Migration from Satis
If you’re migrating from Satis:
-
Remove Satis configuration: Remove your
satis.jsonfile and Satis build process. -
Update repository URLs: Replace Satis URLs in all
composer.jsonfiles:
{ "repositories": [ { "type": "composer", "url": "http://localhost:8080/composer/my-repo" } ]}-
Upload packages: Use the Artifact Keeper API to upload existing packages.
-
Update authentication: Replace Satis auth with Artifact Keeper auth.
Advantages over Satis
- No static file generation required
- Real-time package availability
- Built-in authentication and access control
- API-driven package publishing
- Version management
- Security scanning integration
- No need to rebuild repository after each publish
Hybrid Setup
Use Artifact Keeper for private packages while keeping Packagist for public packages:
{ "repositories": [ { "type": "composer", "url": "http://localhost:8080/composer/my-repo" }, { "packagist.org": true } ]}CI/CD Examples
GitHub Actions
name: Publish Composer Packageon: push: tags: - 'v*'
jobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Set up PHP uses: shivammathur/setup-php@v2 with: php-version: '8.2' tools: composer
- name: Install dependencies run: composer install --no-dev --optimize-autoloader
- name: Create package archive run: | VERSION=${GITHUB_REF#refs/tags/v} ARCHIVE="my-package-${VERSION}.zip" zip -r "$ARCHIVE" . -x "*.git*" "tests/*" "vendor/*" echo "ARCHIVE=$ARCHIVE" >> $GITHUB_ENV echo "VERSION=$VERSION" >> $GITHUB_ENV
- name: Publish to Artifact Keeper run: | curl -X POST \ -F "file=@${{ env.ARCHIVE }}" \ -F "name=mycompany/my-package" \ -F "version=${{ env.VERSION }}" \ -u "${{ secrets.ARTIFACT_KEEPER_USER }}:${{ secrets.ARTIFACT_KEEPER_PASSWORD }}" \ ${{ secrets.ARTIFACT_KEEPER_URL }}/api/v1/composer/my-repo/packagesGitLab CI
publish: image: php:8.2 before_script: - apt-get update && apt-get install -y zip curl - curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer script: - composer install --no-dev --optimize-autoloader - VERSION=${CI_COMMIT_TAG#v} - ARCHIVE="my-package-${VERSION}.zip" - zip -r "$ARCHIVE" . -x "*.git*" "tests/*" "vendor/*" - | curl -X POST \ -F "file=@$ARCHIVE" \ -F "name=mycompany/my-package" \ -F "version=$VERSION" \ -u "$ARTIFACT_KEEPER_USER:$ARTIFACT_KEEPER_PASSWORD" \ $ARTIFACT_KEEPER_URL/api/v1/composer/my-repo/packages only: - tagsJenkins Pipeline
pipeline { agent any
tools { php 'PHP 8.2' }
environment { ARTIFACT_KEEPER_CREDS = credentials('artifact-keeper-credentials') }
stages { stage('Build') { steps { sh 'composer install --no-dev --optimize-autoloader' } }
stage('Package') { steps { script { def version = sh(script: 'git describe --tags --abbrev=0', returnStdout: true).trim() env.VERSION = version.replaceFirst(/^v/, '') env.ARCHIVE = "my-package-${env.VERSION}.zip" } sh 'zip -r $ARCHIVE . -x "*.git*" "tests/*" "vendor/*"' } }
stage('Publish') { steps { sh ''' curl -X POST \ -F "file=@$ARCHIVE" \ -F "name=mycompany/my-package" \ -F "version=$VERSION" \ -u "$ARTIFACT_KEEPER_CREDS" \ $ARTIFACT_KEEPER_URL/api/v1/composer/my-repo/packages ''' } } }}CircleCI
version: 2.1
jobs: publish: docker: - image: php:8.2 steps: - checkout
- run: name: Install dependencies command: | apt-get update && apt-get install -y zip curl curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer composer install --no-dev --optimize-autoloader
- run: name: Create archive command: | VERSION=${CIRCLE_TAG#v} ARCHIVE="my-package-${VERSION}.zip" zip -r "$ARCHIVE" . -x "*.git*" "tests/*" "vendor/*" echo "export ARCHIVE=$ARCHIVE" >> $BASH_ENV echo "export VERSION=$VERSION" >> $BASH_ENV
- run: name: Publish to Artifact Keeper command: | curl -X POST \ -F "file=@$ARCHIVE" \ -F "name=mycompany/my-package" \ -F "version=$VERSION" \ -u "$ARTIFACT_KEEPER_USER:$ARTIFACT_KEEPER_PASSWORD" \ $ARTIFACT_KEEPER_URL/api/v1/composer/my-repo/packages
workflows: version: 2 publish-on-tag: jobs: - publish: filters: tags: only: /^v.*/ branches: ignore: /.*/Troubleshooting
Authentication Errors
Verify authentication configuration:
composer config --listcomposer config --global --listTest authentication:
composer diagnoseRepository Not Found
Check repository URL is correct:
composer config repositoriesVerify the repository exists on the Artifact Keeper server.
Package Not Found
Clear Composer cache:
composer clear-cacheOr:
rm -rf ~/.composer/cacheEnable verbose output:
composer require mycompany/my-package -vvvSSL/TLS Issues
For self-signed certificates, disable SSL verification (not recommended for production):
{ "config": { "secure-http": false }}Or add CA certificate:
composer config cafile /path/to/ca-bundle.crtVersion Constraint Issues
Check available versions:
composer show mycompany/my-package --allDry-run to see what would be installed:
composer update --dry-runMemory Limit Errors
Increase PHP memory limit:
php -d memory_limit=-1 $(which composer) installOr set in composer.json:
{ "config": { "memory-limit": "2G" }}Lock File Issues
If composer.lock is out of sync:
composer update --lockOr regenerate completely:
rm composer.lockcomposer installPlatform Requirements
Override platform requirements (use with caution):
composer install --ignore-platform-reqsOr configure specific requirements:
{ "config": { "platform": { "php": "8.2.0" } }}Best Practices
Semantic Versioning
Follow semantic versioning for your packages:
- Major (1.0.0 -> 2.0.0): Breaking changes
- Minor (1.0.0 -> 1.1.0): New features, backward compatible
- Patch (1.0.0 -> 1.0.1): Bug fixes
Package Metadata
Include essential metadata in composer.json:
{ "name": "mycompany/my-package", "description": "Clear, concise description", "type": "library", "keywords": ["keyword1", "keyword2"], "homepage": "https://github.com/mycompany/my-package", "license": "MIT", "authors": [ { "name": "Your Name", "email": "you@example.com", "homepage": "https://example.com", "role": "Developer" } ], "support": { "email": "support@example.com", "issues": "https://github.com/mycompany/my-package/issues", "source": "https://github.com/mycompany/my-package" }}PSR-4 Autoloading
Use PSR-4 autoloading standard:
{ "autoload": { "psr-4": { "MyCompany\\MyPackage\\": "src/" } }, "autoload-dev": { "psr-4": { "MyCompany\\MyPackage\\Tests\\": "tests/" } }}.gitattributes
Exclude development files from package archives:
/tests export-ignore/.github export-ignore/.gitignore export-ignore/.gitattributes export-ignore/phpunit.xml export-ignore/phpcs.xml export-ignore/.editorconfig export-ignoreLock Dependencies
Commit composer.lock for applications, exclude for libraries:
# For applicationsgit add composer.lock
# For libraries (in .gitignore)composer.lockSee Also
- Security Scanning - Automatic vulnerability scanning for Composer packages
- Security Policies - Configure policies to block vulnerable packages
- PyPI Guide - Python package repository guide
- npm Guide - JavaScript package repository guide