Pages

Thursday, April 3, 2025

Complete Guide to Integrating Tenancy for Laravel v3

Complete Guide to Integrating Tenancy for Laravel v3

Complete Guide to Integrating Tenancy for Laravel v3

Multi-tenancy is a crucial requirement for many modern SaaS applications. The Tenancy for Laravel package (formerly known as hyn/multi-tenant) provides an elegant solution for implementing multi-tenancy in Laravel applications. This guide will walk you through the complete integration process for version 3 of the package.

Prerequisites

  • Laravel 8.x or higher
  • PHP 8.0 or higher
  • Composer installed
  • Database server (MySQL, PostgreSQL, SQLite, or SQL Server)

Step 1: Installation

First, install the package via Composer:

composer require stancl/tenancy

Then, publish the configuration file:

php artisan vendor:publish --provider="Stancl\Tenancy\TenancyServiceProvider" --tag=config
Note: The package was previously known as hyn/multi-tenant. If you're migrating from v2, check the upgrade guide.

Step 2: Database Configuration

Tenancy v3 uses a central database for tenant metadata and separate databases for each tenant. Configure your central database connection in .env:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=central_database
DB_USERNAME=root
DB_PASSWORD=

Configure the tenancy settings in config/tenancy.php:

'database' => [
    'based_on' => 'mysql', // The connection to use as a base for tenant databases
    'prefix' => 'tenant_',
    'suffix' => '',
],

Step 3: Setting Up Tenants

Run the migrations to create the tenants table:

php artisan tenancy:install

Then migrate:

php artisan migrate

Create a Tenant model and migration:

php artisan make:model Tenant -m

Update the migration:

Schema::create('tenants', function (Blueprint $table) {
    $table->string('id')->primary();
    
    // Your custom columns
    $table->string('name');
    $table->string('domain')->unique();
    $table->json('data')->nullable();
    
    $table->timestamps();
});

Step 4: Configuring Routes

Update your routes/web.php to handle tenant routes:

Route::middleware([
    'web',
    InitializeTenancyByDomain::class,
    PreventAccessFromCentralDomains::class,
])->group(function () {
    // Your tenant routes here
    Route::get('/', function () {
        return 'This is your multi-tenant application. The id of the current tenant is ' . tenant('id');
    });
});

// Central domain routes
Route::get('/', function () {
    return 'This is the central domain.';
});

Step 5: Tenant Identification

Configure how tenants are identified in config/tenancy.php:

'tenant_model' => \App\Models\Tenant::class,

'identification_middleware' => [
    InitializeTenancyByDomain::class,
    // Or InitializeTenancyBySubdomain::class,
    // Or InitializeTenancyByPath::class,
],

Step 6: Creating Tenants

Create a tenant programmatically:

$tenant = Tenant::create([
    'id' => 'acme',
    'name' => 'ACME Corp',
    'domain' => 'acme.yourdomain.com',
]);

$tenant->domains()->create([
    'domain' => 'acme.yourdomain.com',
]);
Note: The package will automatically create a database for the tenant when you create the tenant record.

Step 7: Running Tenant-Specific Commands

You can run artisan commands for specific tenants:

php artisan tenancy:run migrate --tenant=acme

Or for all tenants:

php artisan tenancy:run migrate --all

Step 8: Storage Configuration

Configure tenant-specific storage in config/filesystems.php:

'tenant' => [
    'driver' => 'local',
    'root' => storage_path('app/tenant/' . tenant('id')),
],

Step 9: Cache Configuration

Configure tenant-specific cache in config/cache.php:

'tenant' => [
    'driver' => 'database',
    'table' => 'tenant_cache',
    'connection' => 'tenant',
],

Step 10: Queue Configuration

For tenant-aware queues, update your queue configuration:

'connections' => [
    'tenant' => [
        'driver' => 'database',
        'table' => 'jobs',
        'queue' => 'default',
        'retry_after' => 90,
        'after_commit' => false,
    ],
],

Advanced Features

Tenant Assets

Serve tenant-specific assets:

Route::get('/assets/{path}', function ($path) {
    return response()->file(storage_path("app/tenant/" . tenant('id') . "/assets/$path"));
})->where('path', '.*');

Custom Tenant Database Creation

Override the default database creation logic:

Event::listen(TenantCreated::class, function (TenantCreated $event) {
    $event->tenant->run(function () {
        // Custom database setup
        Artisan::call('migrate', [
            '--path' => 'database/migrations/tenant',
            '--force' => true,
        ]);
        
        // Seed data
        Artisan::call('db:seed', [
            '--class' => 'TenantDatabaseSeeder',
        ]);
    });
});

Central Domain Access to Tenant Data

Access tenant data from the central domain:

tenancy()->initialize('tenant-id');
// Now you can access tenant data
tenancy()->end();

Troubleshooting

Common Issues:
  • Make sure your tenant domains are properly configured in your hosts file or DNS
  • Check that your database user has permissions to create databases
  • Verify that your cache and session drivers are tenant-aware
  • Ensure all necessary middleware is applied to your routes

Conclusion

Tenancy for Laravel v3 provides a powerful and flexible solution for implementing multi-tenancy in your Laravel applications. By following this guide, you've set up a robust multi-tenant architecture that can scale with your application's needs.

For more advanced features and customization options, refer to the official documentation.

Laravel Queue System: Complete Guide

Laravel Queue System: Complete Guide

Laravel Queue System: Complete Basic to Advanced Guide

Laravel's queue system allows you to defer the processing of time-consuming tasks, such as sending emails or processing files, to a later time. This significantly improves your application's response time. In this comprehensive guide, we'll cover everything from basic setup to advanced queue techniques.

Table of Contents

Introduction to Laravel Queues

Queues allow you to defer time-consuming tasks to be executed in the background, rather than making your users wait for them to complete during their web request. Common use cases include:

  • Sending emails
  • Processing uploaded files
  • Performing database maintenance
  • Generating reports
  • Calling external APIs
Note: Queues are different from Laravel's scheduler. The scheduler is for running tasks at specific times (like cron jobs), while queues are for deferring tasks to be processed as soon as possible in the background.

Setting Up Queues

Configuration

Laravel supports several queue backends out of the box:

  • Database
  • Redis
  • Amazon SQS
  • Beanstalkd
  • Sync (for local development, runs jobs immediately)

Configure your queue connection in config/queue.php:

'default' => env('QUEUE_CONNECTION', 'sync'),

'connections' => [
    'sync' => [
        'driver' => 'sync',
    ],

    'database' => [
        'driver' => 'database',
        'table' => 'jobs',
        'queue' => 'default',
        'retry_after' => 90,
    ],

    'redis' => [
        'driver' => 'redis',
        'connection' => 'default',
        'queue' => env('REDIS_QUEUE', 'default'),
        'retry_after' => 90,
        'block_for' => null,
    ],
],

Database Driver Setup

If using the database driver, you'll need to create the jobs table:

php artisan queue:table
php artisan migrate

Redis Driver Setup

For Redis, ensure you have the Redis PHP extension and Laravel's Redis package installed:

composer require predis/predis

Configure your Redis connection in config/database.php.

Creating Jobs

Jobs represent the tasks that will be queued. Generate a new job class:

php artisan make:job ProcessPodcast

This creates a file at app/Jobs/ProcessPodcast.php:

<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;

class ProcessPodcast implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        // Process the podcast...
    }
}

Job Structure

  • ShouldQueue interface marks the job as queueable
  • Dispatchable provides the dispatch method
  • InteractsWithQueue allows job to interact with the queue
  • Queueable provides configuration methods like onQueue
  • SerializesModels safely serializes Eloquent models

Passing Data to Jobs

You can pass data to the job through its constructor:

public function __construct(public Podcast $podcast)
{
}
Warning: Be careful when passing large objects to jobs as they will be serialized and stored in your queue backend. Consider passing IDs and re-fetching the data in the job instead.

Dispatching Jobs

Dispatch jobs from anywhere in your application:

// Basic dispatch
ProcessPodcast::dispatch();

// With constructor parameters
ProcessPodcast::dispatch($podcast);

// Delay execution by 10 minutes
ProcessPodcast::dispatch($podcast)
    ->delay(now()->addMinutes(10));

// Specify a queue
ProcessPodcast::dispatch($podcast)
    ->onQueue('processing');

Dispatching From Controllers

public function store(Request $request)
{
    $podcast = Podcast::create($request->validated());
    
    ProcessPodcast::dispatch($podcast);
    
    return redirect()->route('podcasts.index');
}

Dispatching After Response

To dispatch after the HTTP response is sent to the browser:

public function store(Request $request)
{
    $podcast = Podcast::create($request->validated());
    
    ProcessPodcast::dispatchAfterResponse($podcast);
    
    return redirect()->route('podcasts.index');
}

Running Queue Workers

Workers process jobs from the queue. Start a worker:

php artisan queue:work

Worker Options

Option Description
--queue=high,default Process specific queues in order
--tries=3 Number of times to attempt a job
--timeout=60 Maximum seconds a job can run
--sleep=3 Seconds to sleep when no jobs available
--once Only process the next job
--stop-when-empty Stop when the queue is empty

Running Workers in Production

For production, use a process manager like Supervisor to keep workers running:

[program:laravel-worker]
process_name=%(program_name)s_%(process_num)02d
command=php /path/to/artisan queue:work --sleep=3 --tries=3
autostart=true
autorestart=true
user=forge
numprocs=8
redirect_stderr=true
stdout_logfile=/path/to/worker.log

Queue Priorities

Process high priority jobs first:

php artisan queue:work --queue=high,default,low

Queue Connections

Laravel supports multiple queue connections. Configure them in config/queue.php:

'connections' => [
    'redis' => [
        'driver' => 'redis',
        'connection' => 'default',
        'queue' => '{default}',
        'retry_after' => 90,
    ],
    
    'sqs' => [
        'driver' => 'sqs',
        'key' => env('AWS_ACCESS_KEY_ID'),
        'secret' => env('AWS_SECRET_ACCESS_KEY'),
        'prefix' => env('SQS_PREFIX'),
        'queue' => env('SQS_QUEUE'),
        'region' => env('AWS_DEFAULT_REGION'),
    ],
],

Dispatch to a specific connection:

ProcessPodcast::dispatch($podcast)
    ->onConnection('sqs');

Handling Failed Jobs

When a job fails, it will be logged in the failed_jobs table. First, create the table:

php artisan queue:failed-table
php artisan migrate

Configuring Failure Handling

Define a failed method on your job class:

public function failed(Throwable $exception)
{
    // Notify admin of failure
}

Retrying Failed Jobs

View failed jobs:

php artisan queue:failed

Retry a failed job:

php artisan queue:retry 5  # Retry job with ID 5
php artisan queue:retry all # Retry all failed jobs

Delete a failed job:

php artisan queue:forget 5

Job Middleware

Middleware allows you to wrap custom logic around job execution. Create middleware:

php artisan make:middleware RateLimited

Implement the handle method:

public function handle($job, $next)
{
    Redis::throttle('key')
        ->block(0)->allow(1)->every(5)
        ->then(function () use ($job, $next) {
            $next($job);
        }, function () use ($job) {
            $job->release(5);
        });
}

Attach middleware to a job:

public function middleware()
{
    return [new RateLimited];
}

Job Chaining

Chain jobs to run sequentially:

Bus::chain([
    new ProcessPodcast($podcast),
    new OptimizePodcast($podcast),
    new ReleasePodcast($podcast),
])->dispatch();

If any job in the chain fails, the rest won't execute.

Chain with Callbacks

Bus::chain([
    new ProcessPodcast($podcast),
    new OptimizePodcast($podcast),
    function () use ($podcast) {
        $podcast->update(['status' => 'released']);
    },
])->dispatch();

Batch Processing

Laravel 8+ introduced job batching for executing a batch of jobs with completion callback.

$batch = Bus::batch([
    new ProcessPodcast(1),
    new ProcessPodcast(2),
    new ProcessPodcast(3),
])->then(function (Batch $batch) {
    // All jobs completed successfully
})->catch(function (Batch $batch, Throwable $e) {
    // First batch job failure
})->finally(function (Batch $batch) {
    // Executed after all callbacks
})->dispatch();

Batch Methods

Method Description
totalJobs Total jobs in the batch
pendingJobs Jobs not yet processed
failedJobs Number of failed jobs
processedJobs Number of processed jobs
cancel() Cancel the batch
delete() Delete the batch

Laravel Horizon

Horizon provides a dashboard and configuration system for Redis queues.

Installation

composer require laravel/horizon
php artisan horizon:install

Configuration

Configure environments and worker settings in config/horizon.php:

'environments' => [
    'production' => [
        'supervisor-1' => [
            'connection' => 'redis',
            'queue' => ['default'],
            'balance' => 'auto',
            'processes' => 10,
            'tries' => 3,
        ],
    ],
],

Running Horizon

php artisan horizon

For production, run Horizon via Supervisor:

[program:horizon]
process_name=%(program_name)s
command=php /path/to/artisan horizon
autostart=true
autorestart=true
user=forge
redirect_stderr=true
stdout_logfile=/path/to/horizon.log

Best Practices

  • Keep jobs small and focused - Each job should do one thing well
  • Use model IDs instead of full objects - Reduces serialization size
  • Set appropriate timeouts - Prevent jobs from running too long
  • Monitor your queues - Use Horizon or custom monitoring
  • Handle failures gracefully - Implement failed job logic
  • Use separate queues for different workloads - Prioritize important jobs
  • Test your jobs - Write tests for your queueable jobs
  • Consider idempotency - Design jobs to be safely retried
Pro Tip: For heavy queue workloads, consider using Laravel Octane with Swoole or RoadRunner for better performance.

Conclusion

Laravel's queue system is a powerful tool for improving application performance by deferring time-consuming tasks. From basic job dispatching to advanced features like batching and Horizon monitoring, Laravel provides everything you need to build robust background processing into your applications.

By following this guide and implementing queues where appropriate, you can significantly enhance your application's responsiveness and user experience.

Laravel Events and Listeners: A Complete Guide (Basic to Advanced)

Laravel Events and Listeners: Complete Guide

Laravel Events and Listeners: Complete Guide (Basic to Advanced)

Laravel's event system provides a simple observer pattern implementation, allowing you to subscribe and listen for various events that occur in your application. This guide will take you from the basics to advanced implementations of Laravel's event system.

Table of Contents

What are Events and Listeners?

In Laravel, events are a way to decouple various aspects of your application. When an event occurs (is "dispatched"), all registered listeners (or subscribers) are notified.

Events are typically classes that represent something that happened in your application (e.g., UserRegistered, OrderShipped).

Listeners are classes that respond to events by performing some action (e.g., sending a welcome email when a user registers).

Why use events? Events help you follow the Single Responsibility Principle by separating the action (what happened) from the reaction (what to do about it). They make your code more maintainable and easier to test.

Basic Setup

Laravel's event system is ready to use out of the box. The main configuration file is config/event.php, but you'll typically work with the EventServiceProvider.

The EventServiceProvider is located at app/Providers/EventServiceProvider.php and looks like this:

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Event;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        // Example:
        // 'App\Events\OrderShipped' => [
        //     'App\Listeners\SendShipmentNotification',
        // ],
    ];

    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        parent::boot();
    }
}

Creating Events

Events are simple PHP classes that typically contain information about what happened. You can generate an event using Artisan:

php artisan make:event UserRegistered

This will create a new event class in app/Events/UserRegistered.php:

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Queue\SerializesModels;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;

class UserRegistered
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $user;

    /**
     * Create a new event instance.
     *
     * @param  \App\User  $user
     * @return void
     */
    public function __construct($user)
    {
        $this->user = $user;
    }
}

Key traits used in events:

  • Dispatchable: Allows the event to be dispatched
  • InteractsWithSockets: Used for broadcasting
  • SerializesModels: Allows Eloquent models to be serialized

Creating Listeners

Listeners handle the logic that should occur when an event is dispatched. Create a listener with Artisan:

php artisan make:listener SendWelcomeEmail --event=UserRegistered

This creates app/Listeners/SendWelcomeEmail.php:

<?php

namespace App\Listeners;

use App\Events\UserRegistered;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;

class SendWelcomeEmail
{
    /**
     * Create the event listener.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     *
     * @param  UserRegistered  $event
     * @return void
     */
    public function handle(UserRegistered $event)
    {
        // Send welcome email to $event->user
    }
}

Registering Events and Listeners

There are several ways to register event/listener relationships:

1. Via the EventServiceProvider

Add your events and listeners to the $listen array in EventServiceProvider:

protected $listen = [
    'App\Events\UserRegistered' => [
        'App\Listeners\SendWelcomeEmail',
        'App\Listeners\CreateUserProfile',
    ],
];

2. Manually with the Event Facade

You can register listeners in the boot method of EventServiceProvider:

public function boot()
{
    parent::boot();
    
    Event::listen(
        'App\Events\UserRegistered',
        'App\Listeners\SendWelcomeEmail'
    );
}

3. Using Wildcards

You can register listeners that handle multiple events using wildcards:

Event::listen('App\Events\*', function ($eventName, array $data) {
    // Handle all App\Events events
});

Dispatching Events

You can dispatch events in several ways:

1. Using the event() Helper

event(new UserRegistered($user));

2. Using the Event Facade

use Illuminate\Support\Facades\Event;

Event::dispatch(new UserRegistered($user));

3. Using the event's dispatch Method

UserRegistered::dispatch($user);
Tip: If your event doesn't need any data, you can dispatch it without constructor parameters:
event(new SomeEvent());

Event Subscribers

Subscribers are classes that may subscribe to multiple events from within the subscriber class itself. Here's how to create one:

1. Create a Subscriber Class

<?php

namespace App\Listeners;

class UserEventSubscriber
{
    /**
     * Handle user registration events.
     */
    public function handleUserRegistration($event) {
        // Send welcome email
    }

    /**
     * Handle user login events.
     */
    public function handleUserLogin($event) {
        // Log login activity
    }

    /**
     * Register the listeners for the subscriber.
     *
     * @param  \Illuminate\Events\Dispatcher  $events
     * @return void
     */
    public function subscribe($events)
    {
        $events->listen(
            'App\Events\UserRegistered',
            [UserEventSubscriber::class, 'handleUserRegistration']
        );

        $events->listen(
            'App\Events\UserLoggedIn',
            [UserEventSubscriber::class, 'handleUserLogin']
        );
    }
}

2. Register the Subscriber

Add the subscriber to the $subscribe property in EventServiceProvider:

protected $subscribe = [
    'App\Listeners\UserEventSubscriber',
];

Queued Listeners

For time-consuming tasks (like sending emails), you can queue listeners:

<?php

namespace App\Listeners;

use App\Events\UserRegistered;
use Illuminate\Contracts\Queue\ShouldQueue;

class SendWelcomeEmail implements ShouldQueue
{
    public function handle(UserRegistered $event)
    {
        // This will be queued
    }
}

Key points about queued listeners:

  • Implement the ShouldQueue interface
  • Will be processed by your queue worker
  • Can specify queue connection, name, and delay

Customizing Queue Behavior

class SendWelcomeEmail implements ShouldQueue
{
    public $connection = 'sqs';
    public $queue = 'emails';
    public $delay = 60;
    
    // ...
}

Handling Failed Jobs

public function failed(UserRegistered $event, $exception)
{
    // Handle failure
}

Testing Events

Laravel provides helpers for testing events:

1. Asserting an Event was Dispatched

$this->expectsEvents(App\Events\UserRegistered::class);

2. Asserting an Event was Not Dispatched

$this->doesntExpectEvents(App\Events\UserRegistered::class);

3. Fake Events for Testing

// Fake all events
Event::fake();

// Fake specific events
Event::fake([
    UserRegistered::class,
]);

// Assertions
Event::assertDispatched(UserRegistered::class);
Event::assertDispatched(UserRegistered::class, function ($event) use ($user) {
    return $event->user->id === $user->id;
});
Event::assertNotDispatched(OrderShipped::class);

Advanced Patterns

1. Event Sourcing

Store all changes to application state as a sequence of events:

// Instead of:
$user->update(['status' => 'active']);

// Do:
event(new UserStatusChanged($user, 'active'));

2. Domain Events

Create events that represent important business occurrences:

class OrderCompleted
{
    public $order;
    
    public function __construct(Order $order)
    {
        $this->order = $order;
    }
}

3. Event Buses

For complex systems, consider using a dedicated event bus package like:

  • SimpleBus
  • Tactician

4. Event Sourcing with Projections

Rebuild application state from stored events:

// Rebuild user state
$events = Event::where('aggregate_id', $userId)->get();
$user = new User();

foreach ($events as $event) {
    $user->apply($event);
}

Conclusion

Laravel's event system provides a powerful way to decouple components of your application. By following the patterns outlined in this guide, you can create applications that are more maintainable, scalable, and testable.

Key takeaways:

  • Events represent something that happened in your application
  • Listeners respond to events with specific actions
  • The event system helps maintain separation of concerns
  • Queued listeners improve performance for slow operations
  • Laravel provides excellent testing support for events

Start with simple events and listeners, then gradually explore more advanced patterns as your application grows in complexity.

Top Laravel Questions and Answers for Interviews

Top Laravel Interview Questions and Answers

Top Laravel Questions and Answers for Interviews & Learners

Here is a complete list of frequently asked Laravel questions along with detailed answers, ideal for interviews or self-study.

1. What is Laravel?
Laravel is an open-source PHP web application framework following the MVC (Model-View-Controller) architectural pattern. It offers elegant syntax, built-in tools for routing, authentication, ORM, and more, helping developers build scalable web apps easily.
2. What are the main features of Laravel?
Key features include:
  • Blade templating engine
  • Eloquent ORM
  • Artisan command-line tool
  • Routing & Middleware
  • Authentication & Authorization
  • Task Scheduling & Queues
  • Laravel Mix & Asset Management
  • Testing support
  • Laravel Sanctum/Passport for API authentication
3. What is Middleware in Laravel?
Middleware acts as a filter between the request and response. It can be used for authentication, logging, CORS, and more. Example: `auth` middleware checks if a user is authenticated before accessing a route.
4. What is Eloquent ORM?
Eloquent is Laravel's built-in ORM that provides a beautiful and simple ActiveRecord implementation for working with databases. It allows interaction with database tables using models.
5. What are Service Providers in Laravel?
Service providers are the central place for configuring and bootstrapping components in Laravel. They register bindings and services to the Laravel service container. The `AppServiceProvider` is one of the default service providers.
6. Explain Laravel routing.
Laravel routes are defined in `routes/web.php` for web and `routes/api.php` for APIs. You can define routes using `Route::get()`, `Route::post()`, `Route::middleware()` etc. It supports route groups, naming, prefixing, and resourceful routing.
7. What is CSRF protection?
Laravel includes CSRF (Cross-Site Request Forgery) protection automatically for POST, PUT, PATCH, and DELETE requests. A hidden CSRF token is added to each form using `@csrf` Blade directive.
8. What are Laravel Queues?
Queues allow you to defer time-consuming tasks (like email sending, processing jobs) to improve app performance. Laravel supports various queue drivers like Redis, database, SQS, etc.
9. What is Laravel's Blade template engine?
Blade is Laravel's templating engine that allows you to write HTML and PHP logic in `.blade.php` files. It supports template inheritance, control structures like `@if`, `@foreach`, and reusable components.
10. How does Laravel handle authentication?
Laravel provides built-in authentication scaffolding using Laravel UI, Breeze, Jetstream, or Fortify. It includes features like login, registration, password reset, and email verification.
11. What is Laravel Sanctum?
Sanctum provides a simple API token authentication system for SPAs and mobile apps. It uses Laravel's cookie-based session authentication and issues personal access tokens.
12. What is the difference between `hasOne`, `hasMany`, `belongsTo`, and `belongsToMany`?
  • hasOne: One-to-one relationship (e.g., User hasOne Profile)
  • hasMany: One-to-many (e.g., Post hasMany Comments)
  • belongsTo: Inverse of hasOne/hasMany
  • belongsToMany: Many-to-many (e.g., User belongsToMany Roles)
13. What is the purpose of the `.env` file in Laravel?
The `.env` file is used to manage environment-specific configuration such as DB credentials, app name, debug mode, etc. Laravel uses `config()` helper to fetch those values.
14. What is the use of Laravel's `artisan` CLI?
Artisan is Laravel’s command-line tool used to perform various tasks like generating models, migrations, seeding, clearing cache, serving app, etc. Example: `php artisan make:model Post -mcr`.
15. How does Laravel support testing?
Laravel supports PHPUnit for unit and feature testing. Tests are stored in `tests/Feature` and `tests/Unit`. Laravel also provides helper methods like `actingAs()`, `assertSee()`, etc.

Want More?

Let me know in the comments if you want Part 2 with advanced Laravel topics like:

  • Event and Listener system
  • Laravel Livewire / Inertia.js
  • Creating custom service providers
  • Laravel Broadcasting
  • Multi-tenancy with Laravel
  • Laravel and Docker deployment

Wednesday, April 2, 2025

100 PHP Interview Questions and Answers

100 PHP Interview Questions and Answers
Basic PHP Questions
1. What is PHP?
PHP (Hypertext Preprocessor) is a server-side scripting language designed for web development. It is open-source and can be embedded into HTML.
2. What are the common uses of PHP?
PHP is commonly used for:
  • Creating dynamic web pages
  • Handling forms and user input
  • Interacting with databases
  • Creating sessions and cookies
  • Generating PDF files, images, and other media
  • Building web applications and e-commerce sites
3. What is the difference between PHP4 and PHP5?
Major differences include:
  • PHP5 introduced full object-oriented programming support
  • Better MySQL support with the mysqli extension
  • Improved error handling with exceptions
  • New SimpleXML for XML parsing
  • SQLite database support
4. How do you execute a PHP script from the command line?
You can execute a PHP script from the command line by using the command: php filename.php
5. What is the difference between echo and print in PHP?
Both are used to output data, but with differences:
  • echo can take multiple parameters, print can take only one
  • echo is slightly faster than print
  • print returns 1, so it can be used in expressions
  • echo has no return value
Variables and Data Types
6. How do you declare a variable in PHP?
Variables in PHP are declared with a dollar sign ($) followed by the variable name. Example: $variableName = "value";
7. What are the main data types in PHP?
PHP supports eight primitive data types:
  • 4 scalar types: boolean, integer, float (double), string
  • 2 compound types: array, object
  • 2 special types: resource, NULL
8. What is the difference between == and === in PHP?
  • == checks for equality (value only)
  • === checks for identity (both value and type)
Example: 0 == "0" is true, but 0 === "0" is false
9. How do you check if a variable is set and not null?
Use the isset() function: if(isset($variable)) { ... }
10. What is variable scope in PHP?
Variable scope defines where a variable can be accessed:
  • Local scope: Only accessible within the function where declared
  • Global scope: Accessible anywhere, but needs global keyword inside functions
  • Static variables: Retain value between function calls
Operators and Control Structures
11. What are the different types of operators in PHP?
PHP has several types of operators:
  • Arithmetic operators (+, -, *, /, %)
  • Assignment operators (=, +=, -=, etc.)
  • Comparison operators (==, ===, !=, <>, !==, >, <, etc.)
  • Logical operators (&&, ||, !, and, or, xor)
  • String operators (., .=)
  • Array operators (+, ==, ===, !=, !==, <>)
12. How does the ternary operator work in PHP?
The ternary operator is a shorthand for if-else: $result = (condition) ? value_if_true : value_if_false;
13. What is the difference between break and continue?
  • break ends execution of the current loop or switch structure
  • continue skips the rest of the current loop iteration and continues with the next iteration
14. How do you write a switch statement in PHP?
Example:
switch($variable) {
    case 'value1':
        // code
        break;
    case 'value2':
        // code
        break;
    default:
        // default code
}
15. What is the purpose of the goto statement in PHP?
The goto statement allows jumping to another section in the program. Example:
goto mylabel;
// some code
mylabel:
// code to execute after goto
Note: goto is generally discouraged as it can make code harder to follow.
Functions
16. How do you define a function in PHP?
Example:
function functionName($param1, $param2) {
    // function code
    return $result;
}
17. What are variable functions in PHP?
Variable functions allow you to call a function using a variable. Example:
function hello() { echo "Hello"; }
$func = 'hello';
$func(); // Calls hello()
18. How do you pass arguments by reference?
Use an ampersand (&) before the parameter in the function definition:
function addFive(&$num) {
    $num += 5;
}
$value = 10;
addFive($value); // $value is now 15
19. What are anonymous functions in PHP?
Anonymous functions (closures) are functions without a name. Example:
$greet = function($name) {
    echo "Hello $name";
};
$greet("World");
20. How do you return multiple values from a function?
You can return multiple values by:
  • Returning an array: return array($value1, $value2);
  • Using references in parameters
  • Returning an object
Arrays
21. How do you create an array in PHP?
  • Indexed array: $array = array("apple", "banana", "cherry");
  • Associative array: $array = array("a"=>"apple", "b"=>"banana");
  • Short syntax (PHP 5.4+): $array = ["apple", "banana"];
22. How do you add an element to an array?
  • For indexed arrays: $array[] = "new value";
  • For associative arrays: $array["key"] = "value";
  • Using array_push(): array_push($array, "value1", "value2");
23. How do you sort an array in PHP?
PHP provides several sorting functions:
  • sort() - sort indexed arrays in ascending order
  • rsort() - sort indexed arrays in descending order
  • asort() - sort associative arrays by value in ascending order
  • ksort() - sort associative arrays by key in ascending order
  • arsort() - sort associative arrays by value in descending order
  • krsort() - sort associative arrays by key in descending order
24. What is the difference between array_merge and array_combine?
  • array_merge() merges two or more arrays into one
  • array_combine() creates an array by using one array for keys and another for values
Example:
$keys = ['a', 'b'];
$values = [1, 2];
$combined = array_combine($keys, $values); // ['a'=>1, 'b'=>2]
25. How do you check if a value exists in an array?
Use in_array() for values: if(in_array($value, $array)) { ... }
Use array_key_exists() for keys: if(array_key_exists($key, $array)) { ... }
Strings
26. How do you concatenate strings in PHP?
Use the dot (.) operator: $full = $str1 . $str2;
Or the concatenation assignment operator: $str1 .= $str2;
27. How do you find the length of a string?
Use strlen(): $length = strlen($string);
28. How do you replace text in a string?
Use str_replace():
$newString = str_replace("old", "new", $originalString);
29. What is the difference between single and double quotes in PHP?
  • Single quotes: Literal strings, no variable interpolation or escape sequences (except \\ and \')
  • Double quotes: Parse variables and escape sequences like \n, \t, etc.
30. How do you convert a string to lowercase or uppercase?
Use strtolower() or strtoupper():
$lower = strtolower("HELLO"); // "hello"
$upper = strtoupper("hello"); // "HELLO"
Object-Oriented PHP
31. What are the main principles of OOP in PHP?
The four main principles are:
  • Encapsulation: Bundling data and methods that work on that data
  • Abstraction: Hiding complex implementation details
  • Inheritance: Creating new classes from existing ones
  • Polymorphism: Using a single interface for different data types
32. How do you define a class in PHP?
Example:
class MyClass {
    // Properties
    public $property;
    
    // Methods
    public function myMethod() {
        // method code
    }
}
33. What is the difference between public, private, and protected?
  • public: Accessible from anywhere
  • private: Accessible only within the class
  • protected: Accessible within the class and its child classes
34. What is a constructor in PHP?
A constructor is a special method (__construct()) that is automatically called when an object is created. Example:
class MyClass {
    public function __construct() {
        echo "Object created";
    }
}
$obj = new MyClass(); // Outputs "Object created"
35. What is method chaining in PHP?
Method chaining allows calling multiple methods in a single statement by returning $this from each method. Example:
class Chainable {
    public function method1() {
        // code
        return $this;
    }
    public function method2() {
        // code
        return $this;
    }
}
$obj = new Chainable();
$obj->method1()->method2();
Forms and User Input
36. How do you retrieve form data submitted with GET method?
Use the $_GET superglobal: $value = $_GET['field_name'];
37. How do you retrieve form data submitted with POST method?
Use the $_POST superglobal: $value = $_POST['field_name'];
38. How do you check if a form has been submitted?
Example:
if($_SERVER['REQUEST_METHOD'] == 'POST') {
    // Form submitted
}
Or check for a specific submit button:
if(isset($_POST['submit'])) {
    // Form submitted
}
39. How do you prevent XSS attacks in PHP forms?
Use htmlspecialchars() to escape output:
echo htmlspecialchars($_POST['input'], ENT_QUOTES, 'UTF-8');
Also consider:
  • Input validation
  • Content Security Policy (CSP) headers
  • Using prepared statements for database queries
40. How do you upload a file in PHP?
Example:
<form method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    <input type="submit">
</form>

<?php
if(isset($_FILES['file'])) {
    $target = "uploads/" . basename($_FILES['file']['name']);
    move_uploaded_file($_FILES['file']['tmp_name'], $target);
}
?>
Sessions and Cookies
41. How do you start a session in PHP?
Use session_start() at the beginning of your script:
<?php
session_start();
$_SESSION['user'] = "John";
?>
42. How do you destroy a session?
<?php
session_start();
session_unset(); // removes all session variables
session_destroy(); // destroys the session
?>
43. How do you set a cookie in PHP?
Use setcookie():
setcookie("name", "value", time()+3600, "/"); // expires in 1 hour
44. How do you retrieve a cookie value?
Use the $_COOKIE superglobal: $value = $_COOKIE['name'];
45. What is the difference between sessions and cookies?
  • Sessions are stored on the server, cookies on the client
  • Sessions are more secure as data isn't sent to the client
  • Cookies have size limits (typically 4KB), sessions don't
  • Cookies can persist after browser is closed, sessions typically don't
Database Interaction
46. How do you connect to a MySQL database in PHP?
Using mysqli:
$conn = new mysqli("hostname", "username", "password", "database");
if($conn->connect_error) {
    die("Connection failed: " . $conn->connect_error);
}
Using PDO:
try {
    $conn = new PDO("mysql:host=hostname;dbname=database", "username", "password");
} catch(PDOException $e) {
    die("Connection failed: " . $e->getMessage());
}
47. What is the difference between mysqli and PDO?
  • PDO supports multiple databases, mysqli is MySQL-specific
  • PDO has named parameters in prepared statements
  • mysqli has some MySQL-specific features not in PDO
  • PDO has a consistent API across databases
48. How do you prevent SQL injection in PHP?
Use prepared statements:
  • With mysqli:
    $stmt = $conn->prepare("SELECT * FROM users WHERE email = ?");
    $stmt->bind_param("s", $email);
    $stmt->execute();
  • With PDO:
    $stmt = $conn->prepare("SELECT * FROM users WHERE email = :email");
    $stmt->bindParam(':email', $email);
    $stmt->execute();
49. How do you fetch data from a MySQL database?
  • mysqli procedural:
    $result = mysqli_query($conn, "SELECT * FROM table");
    while($row = mysqli_fetch_assoc($result)) {
        echo $row['column'];
    }
  • mysqli object-oriented:
    $result = $conn->query("SELECT * FROM table");
    while($row = $result->fetch_assoc()) {
        echo $row['column'];
    }
  • PDO:
    $stmt = $conn->query("SELECT * FROM table");
    while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        echo $row['column'];
    }
50. How do you insert data into a MySQL database?
Using prepared statements with mysqli:
$stmt = $conn->prepare("INSERT INTO users (name, email) VALUES (?, ?)");
$stmt->bind_param("ss", $name, $email);
$stmt->execute();
With PDO:
$stmt = $conn->prepare("INSERT INTO users (name, email) VALUES (:name, :email)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':email', $email);
$stmt->execute();
Error Handling
51. How do you handle errors in PHP?
PHP provides several error handling methods:
  • Basic error handling with die(): if(!file) die("Error: File not found");
  • Custom error handlers with set_error_handler()
  • Exceptions with try-catch blocks
  • Error reporting configuration in php.ini
52. What is the difference between exceptions and errors?
  • Errors are problems that should not occur in normal operation (syntax errors, fatal errors)
  • Exceptions are exceptional conditions that can be caught and handled programmatically
  • Exceptions can be thrown and caught, errors typically can't
53. How do you create a custom exception handler?
Example:
function customExceptionHandler($exception) {
    echo "Custom handler: " . $exception->getMessage();
}
set_exception_handler('customExceptionHandler');

throw new Exception("Something went wrong");
54. What are the different error levels in PHP?
Common error levels:
  • E_ERROR: Fatal run-time errors
  • E_WARNING: Non-fatal run-time errors
  • E_PARSE: Compile-time parse errors
  • E_NOTICE: Run-time notices
  • E_STRICT: Suggestions for forward compatibility
  • E_ALL: All errors and warnings
55. How do you log errors to a file in PHP?
Configure in php.ini or use ini_set():
ini_set('log_errors', 1);
ini_set('error_log', '/path/to/error.log');
Or use error_log() function:
error_log("Error message", 3, "/path/to/error.log");
File Handling
56. How do you read a file in PHP?
Several methods:
  • file_get_contents(): $content = file_get_contents("file.txt");
  • fopen() with fread():
    $file = fopen("file.txt", "r");
    $content = fread($file, filesize("file.txt"));
    fclose($file);
  • file(): $lines = file("file.txt"); (reads into array)
57. How do you write to a file in PHP?
Several methods:
  • file_put_contents(): file_put_contents("file.txt", $content);
  • fopen() with fwrite():
    $file = fopen("file.txt", "w");
    fwrite($file, $content);
    fclose($file);
58. How do you check if a file exists?
Use file_exists(): if(file_exists("file.txt")) { ... }
59. How do you delete a file in PHP?
Use unlink(): unlink("file.txt");
60. How do you get file information (size, type, etc.)?
Several functions:
  • filesize(): $size = filesize("file.txt");
  • filetype(): $type = filetype("file.txt");
  • pathinfo(): $info = pathinfo("file.txt");
  • finfo_file(): For MIME type detection
Security
61. How do you hash passwords in PHP?
Use password_hash() and password_verify():
// Hashing
$hash = password_hash($password, PASSWORD_DEFAULT);

// Verifying
if(password_verify($input_password, $hash)) {
    // Password correct
}
62. What is CSRF and how do you prevent it?
CSRF (Cross-Site Request Forgery) is an attack that tricks users into performing unwanted actions. Prevention methods:
  • Use CSRF tokens in forms
  • Check the Referer header
  • Implement SameSite cookies
  • Require re-authentication for sensitive actions
63. How do you sanitize user input in PHP?
Methods include:
  • filter_var(): $clean = filter_var($input, FILTER_SANITIZE_STRING);
  • htmlspecialchars() for output
  • Prepared statements for database queries
  • Regular expressions for pattern validation
64. What is SQL injection and how do you prevent it?
SQL injection is an attack where malicious SQL is inserted into queries. Prevention:
  • Always use prepared statements with parameterized queries
  • Use ORMs or query builders
  • Validate and sanitize all input
  • Follow the principle of least privilege for database users
65. How do you secure PHP sessions?
Session security measures:
  • Use session_regenerate_id() after login
  • Set session.cookie_httponly and session.cookie_secure in php.ini
  • Store sessions in a secure location
  • Set appropriate session timeouts
  • Validate session data
PHP Functions and Features
66. What are magic methods in PHP?
Magic methods are special methods that start with __. Common ones:
  • __construct(): Class constructor
  • __destruct(): Class destructor
  • __get(), __set(): Property access
  • __call(), __callStatic(): Method overloading
  • __toString(): Object to string conversion
67. What is autoloading in PHP?
Autoloading automatically loads class files when they're needed. Example with spl_autoload_register():
spl_autoload_register(function ($class) {
    include 'classes/' . $class . '.class.php';
});
68. What are traits in PHP?
Traits are a mechanism for code reuse in single inheritance languages. Example:
trait Loggable {
    public function log($msg) {
        echo $msg;
    }
}

class User {
    use Loggable;
}

$user = new User();
$user->log("Message");
69. What are generators in PHP?
Generators provide an easy way to implement iterators without creating a class. Example:
function xrange($start, $end) {
    for($i = $start; $i <= $end; $i++) {
        yield $i;
    }
}

foreach(xrange(1, 10) as $num) {
    echo $num;
}
70. What are namespaces in PHP?
Namespaces prevent name collisions between code. Example:
namespace MyProject;

class MyClass {
    // class code
}

$obj = new \MyProject\MyClass();
PHP and Web Services
71. How do you make a GET request in PHP?
Using file_get_contents():
$response = file_get_contents('http://example.com/api?param=value');
Using cURL:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://example.com/api?param=value');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
72. How do you make a POST request in PHP?
Using file_get_contents():
$options = [
    'http' => [
        'method' => 'POST',
        'content' => http_build_query(['key' => 'value'])
    ]
];
$context = stream_context_create($options);
$response = file_get_contents('http://example.com/api', false, $context);
Using cURL:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'http://example.com/api');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, ['key' => 'value']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
73. How do you parse JSON in PHP?
Use json_decode():
$json = '{"name":"John","age":30}';
$data = json_decode($json);
echo $data->name; // John
For associative arrays:
$data = json_decode($json, true);
echo $data['name']; // John
74. How do you create a REST API in PHP?
Basic example:
header("Content-Type: application/json");

$method = $_SERVER['REQUEST_METHOD'];
$request = explode("/", trim($_SERVER['PATH_INFO'],'/'));

switch($method) {
    case 'GET':
        // Handle GET request
        echo json_encode(["message" => "GET response"]);
        break;
    case 'POST':
        // Handle POST request
        $input = json_decode(file_get_contents('php://input'), true);
        echo json_encode(["received" => $input]);
        break;
    // Other methods...
}
75. How do you handle CORS in PHP?
Set appropriate headers:
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
header("Access-Control-Allow-Headers: Content-Type");
For preflight requests:
if($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    header("HTTP/1.1 200 OK");
    exit();
}
Performance and Optimization
76. How do you optimize PHP performance?
Optimization techniques:
  • Use OPcache (opcode caching)
  • Optimize database queries and use indexing
  • Minimize file operations
  • Use efficient data structures and algorithms
  • Implement caching (APCu, Redis, Memcached)
  • Use a PHP accelerator
  • Profile code with Xdebug
77. What is OPcache and how does it work?
OPcache improves PHP performance by storing precompiled script bytecode in shared memory, eliminating the need for PHP to load and parse scripts on each request. Enable in php.ini:
zend_extension=opcache.so
opcache.enable=1
opcache.memory_consumption=128
opcache.max_accelerated_files=4000
78. How do you profile PHP code?
Use tools like:
  • Xdebug with KCacheGrind or QCacheGrind
  • Blackfire.io
  • New Relic
  • Built-in microtime() for simple profiling
79. What are some common PHP performance bottlenecks?
Common bottlenecks:
  • Inefficient database queries
  • Excessive file operations
  • Memory leaks
  • Unoptimized loops
  • Unnecessary object instantiation
  • Large arrays or data structures
  • Network calls
80. How do you implement caching in PHP?
Caching methods:
  • OPcache for bytecode caching
  • APCu for user data caching
  • Memcached or Redis for distributed caching
  • File-based caching
  • HTTP caching headers
  • Varnish or other reverse proxy caching
PHP Frameworks
81. What are some popular PHP frameworks?
Popular PHP frameworks:
  • Laravel
  • Symfony
  • CodeIgniter
  • Zend Framework / Laminas
  • CakePHP
  • Yii
  • Phalcon
  • Slim (micro-framework)
82. What is Composer and how is it used?
Composer is a dependency manager for PHP. Usage:
  • Install packages: composer require package/name
  • Autoloading: require 'vendor/autoload.php';
  • Manage dependencies in composer.json
83. What is MVC and how is it implemented in PHP?
MVC (Model-View-Controller) is an architectural pattern:
  • Model: Handles data and business logic
  • View: Handles presentation and user interface
  • Controller: Handles user input and coordinates model/view
Example in PHP frameworks like Laravel or CodeIgniter.
84. What are some advantages of using a PHP framework?
Advantages:
  • Faster development
  • Code organization and structure
  • Built-in security features
  • Community support
  • Reusable components
  • Following best practices
  • Database abstraction
85. What is Laravel and what are its key features?
Laravel is a popular PHP framework with features:
  • Eloquent ORM
  • Blade templating engine
  • Artisan command-line tool
  • Middleware
  • Authentication system
  • Routing
  • Migrations
  • Testing support
Advanced PHP Concepts
86. What are PHP closures?
Closures are anonymous functions that can access variables from the parent scope. Example:
$message = 'hello';
$closure = function() use ($message) {
    echo $message;
};
$closure(); // outputs "hello"
87. What is dependency injection in PHP?
Dependency injection is a technique where dependencies are "injected" into a class rather than created within it. Example:
class Logger {
    public function log($message) { /* ... */ }
}

class UserService {
    private $logger;
    
    public function __construct(Logger $logger) {
        $this->logger = $logger;
    }
    
    public function createUser() {
        $this->logger->log("User created");
    }
}

$logger = new Logger();
$userService = new UserService($logger);
88. What are PHP attributes (annotations)?
Attributes (introduced in PHP 8) provide structured metadata. Example:
#[Route("/api/posts", methods: ["GET"])]
class PostController {
    #[ORM\Column(type: "string")]
    public $title;
}
89. What is type hinting in PHP?
Type hinting allows specifying expected types for parameters and return values. Example:
function addNumbers(int $a, int $b): int {
    return $a + $b;
}
90. What are PHP enums?
Enums (introduced in PHP 8.1) are a special kind of class for enumerations. Example:
enum Status {
    case DRAFT;
    case PUBLISHED;
    case ARCHIVED;
}

$status = Status::PUBLISHED;
PHP 8 Features
91. What are some key features of PHP 8?
PHP 8 features:
  • Just-In-Time (JIT) compilation
  • Named arguments
  • Attributes (annotations)
  • Union types
  • Match expression
  • Constructor property promotion
  • Nullsafe operator
  • Stringable interface
  • New str_contains() function
92. What is the nullsafe operator in PHP 8?
The nullsafe operator (?->) short-circuits if the left-hand operand is null. Example:
// Instead of:
$country = $user?->getAddress()?->getCountry();

// Old way:
$country = null;
if($user !== null) {
    $address = $user->getAddress();
    if($address !== null) {
        $country = $address->getCountry();
    }
}
93. What are named arguments in PHP 8?
Named arguments allow passing arguments by parameter name. Example:
function createUser($name, $age, $email) { /* ... */ }

// Using named arguments:
createUser(age: 30, email: 'test@example.com', name: 'John');
94. What is the match expression in PHP 8?
The match expression is a more powerful switch alternative. Example:
$result = match($statusCode) {
    200, 201 => 'success',
    404 => 'not found',
    500 => 'server error',
    default => 'unknown status',
};
95. What is constructor property promotion in PHP 8?
Constructor property promotion simplifies property declaration. Example:
// Before:
class User {
    private string $name;
    private int $age;
    
    public function __construct(string $name, int $age) {
        $this->name = $name;
        $this->age = $age;
    }
}

// With property promotion:
class User {
    public function __construct(
        private string $name,
        private int $age
    ) {}
}
Miscellaneous
96. How do you debug PHP code?
Debugging methods:
  • var_dump(), print_r() for quick inspection
  • error_log() for logging
  • Xdebug for step debugging
  • PHP's built-in web server with error reporting
  • IDE debuggers
  • Tracing with debug_backtrace()
97. How do you implement internationalization in PHP?
Internationalization methods:
  • gettext extension
  • Locale-aware number/date formatting
  • UTF-8 support
  • Storing translations in arrays or databases
  • Using frameworks' i18n features
98. How do you work with dates and times in PHP?
Use the DateTime class:
$date = new DateTime('now');
echo $date->format('Y-m-d H:i:s');

// Date arithmetic
$date->add(new DateInterval('P10D')); // Add 10 days

// Timezone handling
$date = new DateTime('now', new DateTimeZone('America/New_York'));
99. How do you create a cron job in PHP?
Create a PHP script and set up a cron entry:
# Edit crontab with: crontab -e
# Run script every day at 2am
0 2 * * * /usr/bin/php /path/to/script.php
100. What are PHP standards recommendations (PSR)?
PSRs are standards by PHP-FIG (Framework Interop Group):
  • PSR-1: Basic coding standard
  • PSR-4: Autoloading standard
  • PSR-7: HTTP message interfaces
  • PSR-12: Extended coding style guide
  • PSR-15: HTTP handlers
They promote interoperability between PHP frameworks and libraries.

Integrating PayHere Payment Gateway in PHP

How to Integrate PayHere Payment Gateway in PHP - Complete Guide

How to Integrate PayHere Payment Gateway in PHP – Complete Guide

PayHere is one of Sri Lanka's most popular payment gateways, offering seamless online payment solutions for businesses. If you're running an e-commerce store, SaaS platform, or any web application that requires payments, integrating PayHere can help you accept credit/debit cards, bank transfers, and mobile wallets securely.

In this step-by-step guide, we'll cover:

  1. PayHere Payment Gateway Overview
  2. Prerequisites for Integration
  3. Setting Up PayHere Sandbox Account
  4. PHP Integration Code (Complete Working Example)
  5. Handling Payment Notifications (IPN)
  6. Testing & Going Live
  7. Common Issues & Troubleshooting
Note: This guide assumes you have basic knowledge of PHP and web development concepts.

1. PayHere Payment Gateway Overview

PayHere supports:

  • One-time payments
  • Recurring/subscription payments
  • Mobile and online banking
  • Visa/Mastercard payments
  • Real-time payment notifications

It's widely used in Sri Lanka and is ideal for businesses looking for a local, secure, and easy-to-integrate payment solution.

2. Prerequisites for Integration

Before integrating PayHere, ensure you have:

  • A PayHere merchant account (Sign up here)
  • A web server with PHP (PHP 7.0+ recommended)
  • SSL certificate (HTTPS required for security)
  • Basic knowledge of PHP and HTML
Important: PayHere requires all transactions to be conducted over HTTPS. Make sure your website has SSL installed before proceeding.

3. Setting Up PayHere Sandbox Account

Before going live, test your integration in sandbox mode:

  1. Go to PayHere Developer Dashboard
  2. Register for a sandbox merchant account
  3. Get your Merchant ID and Merchant Secret (keep these secure!)

4. PHP Integration Code (Complete Working Example)

Here's a full implementation of PayHere in PHP:

Step 1: Create the Payment Form (payment.php)

<?php
// PayHere Configuration
$merchant_id = "your_merchant_id"; // Replace with your sandbox ID
$merchant_secret = "your_merchant_secret"; // Keep this secret!

// Generate a unique order ID
$order_id = uniqid();
$amount = "1000.00"; // LKR
$currency = "LKR";

// Calculate the secure hash
$hash = strtoupper(
    md5(
        $merchant_id . 
        $order_id . 
        number_format($amount, 2, '.', '') . 
        $currency .  
        strtoupper(md5($merchant_secret))
    )
);
?>

<!DOCTYPE html>
<html>
<head>
    <title>PayHere Payment Integration</title>
</head>
<body>
    <h1>Complete Your Payment</h1>
    <form method="post" action="https://sandbox.payhere.lk/pay/checkout">
        <!-- Required Fields -->
        <input type="hidden" name="merchant_id" value="<?php echo $merchant_id; ?>">
        <input type="hidden" name="return_url" value="https://yourwebsite.com/return.php">
        <input type="hidden" name="cancel_url" value="https://yourwebsite.com/cancel.php">
        <input type="hidden" name="notify_url" value="https://yourwebsite.com/notify.php">
        
        <!-- Order Details -->
        <input type="hidden" name="order_id" value="<?php echo $order_id; ?>">
        <input type="hidden" name="items" value="Test Product">
        <input type="hidden" name="currency" value="<?php echo $currency; ?>">
        <input type="hidden" name="amount" value="<?php echo $amount; ?>">
        
        <!-- Customer Details -->
        <input type="hidden" name="first_name" value="John">
        <input type="hidden" name="last_name" value="Doe">
        <input type="hidden" name="email" value="customer@example.com">
        <input type="hidden" name="phone" value="0771234567">
        <input type="hidden" name="address" value="No.1, Galle Road">
        <input type="hidden" name="city" value="Colombo">
        <input type="hidden" name="country" value="Sri Lanka">
        
        <!-- Security Hash -->
        <input type="hidden" name="hash" value="<?php echo $hash; ?>">
        
        <button type="submit">Pay with PayHere</button>
    </form>
</body>
</html>
Security Tip: Never expose your Merchant Secret in client-side code. The hash calculation should always be done server-side.

Step 2: Handle Payment Notification (notify.php)

<?php
// Validate PayHere IPN (Instant Payment Notification)
function verifyPayment($merchant_secret) {
    $merchant_id = $_POST['merchant_id'];
    $order_id = $_POST['order_id'];
    $amount = $_POST['payhere_amount'];
    $currency = $_POST['payhere_currency'];
    $status_code = $_POST['status_code'];
    $md5sig = $_POST['md5sig'];
    
    // Recompute the hash for verification
    $local_md5sig = strtoupper(
        md5(
            $merchant_id . $order_id . $amount . 
            $currency . $status_code . 
            strtoupper(md5($merchant_secret))
        )
    );
    
    // Check if the signature matches and payment is successful
    return ($local_md5sig === $md5sig && $status_code == 2);
}

// Your Merchant Secret
$merchant_secret = "your_merchant_secret";

if (verifyPayment($merchant_secret)) {
    // Payment is successful
    $order_id = $_POST['order_id'];
    $amount = $_POST['payhere_amount'];
    
    // Update your database or trigger order fulfillment
    file_put_contents('payments.log', "SUCCESS: Order $order_id, Amount $amount\n", FILE_APPEND);
    
    // Return HTTP 200 to PayHere
    header("HTTP/1.1 200 OK");
} else {
    // Payment failed or verification error
    file_put_contents('payments.log', "FAILED: " . json_encode($_POST) . "\n", FILE_APPEND);
    header("HTTP/1.1 400 Bad Request");
}
?>

Step 3: Handle Return URL (return.php)

<?php
$order_id = $_GET['order_id'];
$status = $_GET['status'];

if ($status === 'success') {
    echo "<h1>Payment Successful!</h1>";
    echo "<p>Thank you for your payment. Order ID: <strong>$order_id</strong></p>";
} else {
    echo "<h1>Payment Cancelled</h1>";
    echo "<p>Your payment was not completed. Order ID: <strong>$order_id</strong></p>";
}
?>

5. Testing & Going Live

Testing in Sandbox Mode

  1. Use sandbox credentials (merchant_id & merchant_secret)
  2. Test with PayHere's test cards:
    • Visa: 4111 1111 1111 1111 (any expiry/CVV)
    • Mastercard: 5555 5555 5555 4444

Going Live

  1. Replace sandbox.payhere.lk with www.payhere.lk
  2. Use your live merchant credentials
  3. Ensure your site has SSL (HTTPS)
Pro Tip: Before going live, thoroughly test all scenarios including successful payments, cancellations, and IPN verification.

6. Common Issues & Troubleshooting

Issue Solution
Payment not redirecting Check if merchant_id is correct
IPN not working Ensure notify_url is HTTPS
Hash verification failed Double-check merchant_secret
"Invalid Amount" error Format amount as 1000.00 (2 decimal places)

7. Conclusion

Integrating PayHere in PHP is straightforward if you follow these steps:

  1. Set up sandbox testing
  2. Generate a secure hash for each transaction
  3. Handle IPN properly to confirm payments
  4. Test thoroughly before going live

If you need recurring payments, check PayHere's subscription API documentation.

Final Notes:

Would you like me to add Laravel-specific integration or WordPress plugin instructions? Let me know in the comments! 👇

Back to Top

Fiverr Fee Calculator – Know What You Really Earn or Pay!

Fiverr Fee Calculator – Know What You Really Earn or Pay! 💸 "How much will I actually earn after Fiverr takes its cut?...