Skip to content

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-repo

Replace my-repo with your repository name.

Format Key

When configuring Artifact Keeper, use the format key:

composer

Configuration

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:

Terminal window
composer config --global repositories.artifact-keeper composer http://localhost:8080/composer/my-repo

View global configuration:

Terminal window
composer config --global --list

Multiple 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:

Terminal window
composer config --global http-basic.localhost:8080 your-username your-password

Or for bearer tokens:

Terminal window
composer config --global bearer.localhost:8080 your-auth-token

Environment Variables

Use environment variables for CI/CD:

Terminal window
export COMPOSER_AUTH='{"http-basic":{"localhost:8080":{"username":"user","password":"pass"}}}'
composer install

Publishing 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:

Terminal window
# Create zip archive
zip -r mycompany-my-package-1.0.0.zip . -x "*.git*" "tests/*" "vendor/*"
# Or use tar
tar -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:

Terminal window
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/packages

Automated Publishing with Git Tags

Create a script to automatically publish from Git tags:

publish-composer.sh
#!/bin/bash
VERSION=$(git describe --tags --abbrev=0)
PACKAGE_NAME="mycompany/my-package"
ARCHIVE="${PACKAGE_NAME//\//-}-${VERSION}.zip"
# Create archive from git tag
git archive --format=zip --prefix="${PACKAGE_NAME//\//-}/" -o "$ARCHIVE" "$VERSION"
# Upload to Artifact Keeper
curl -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

Terminal window
composer require mycompany/my-package

Install from composer.json

Terminal window
composer install

Install Specific Version

Terminal window
composer require mycompany/my-package:1.0.0
composer require mycompany/my-package:^1.0
composer require mycompany/my-package:~1.2.3

Install with Development Dependencies

Terminal window
composer install --dev

Install without Development Dependencies

Terminal window
composer install --no-dev

Update Packages

Terminal window
# Update all packages
composer update
# Update specific package
composer update mycompany/my-package
# Update to latest minor version
composer update mycompany/my-package --with-dependencies

Version 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:

  1. Remove Satis configuration: Remove your satis.json file and Satis build process.

  2. Update repository URLs: Replace Satis URLs in all composer.json files:

{
"repositories": [
{
"type": "composer",
"url": "http://localhost:8080/composer/my-repo"
}
]
}
  1. Upload packages: Use the Artifact Keeper API to upload existing packages.

  2. 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 Package
on:
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/packages

GitLab 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:
- tags

Jenkins 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:

Terminal window
composer config --list
composer config --global --list

Test authentication:

Terminal window
composer diagnose

Repository Not Found

Check repository URL is correct:

Terminal window
composer config repositories

Verify the repository exists on the Artifact Keeper server.

Package Not Found

Clear Composer cache:

Terminal window
composer clear-cache

Or:

Terminal window
rm -rf ~/.composer/cache

Enable verbose output:

Terminal window
composer require mycompany/my-package -vvv

SSL/TLS Issues

For self-signed certificates, disable SSL verification (not recommended for production):

{
"config": {
"secure-http": false
}
}

Or add CA certificate:

Terminal window
composer config cafile /path/to/ca-bundle.crt

Version Constraint Issues

Check available versions:

Terminal window
composer show mycompany/my-package --all

Dry-run to see what would be installed:

Terminal window
composer update --dry-run

Memory Limit Errors

Increase PHP memory limit:

Terminal window
php -d memory_limit=-1 $(which composer) install

Or set in composer.json:

{
"config": {
"memory-limit": "2G"
}
}

Lock File Issues

If composer.lock is out of sync:

Terminal window
composer update --lock

Or regenerate completely:

Terminal window
rm composer.lock
composer install

Platform Requirements

Override platform requirements (use with caution):

Terminal window
composer install --ignore-platform-reqs

Or 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:

.gitattributes
/tests export-ignore
/.github export-ignore
/.gitignore export-ignore
/.gitattributes export-ignore
/phpunit.xml export-ignore
/phpcs.xml export-ignore
/.editorconfig export-ignore

Lock Dependencies

Commit composer.lock for applications, exclude for libraries:

# For applications
git add composer.lock
# For libraries (in .gitignore)
composer.lock

See Also