PHP code example of moffhub / ussd

1. Go to this page and download the library: Download moffhub/ussd library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

moffhub / ussd example snippets




namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Moffhub\Ussd\UssdFramework;
use Moffhub\Ussd\Menus\SimpleMenu;
use Moffhub\Ussd\UssdResponse;

class UssdController extends Controller
{
    public function handle(Request $request)
    {
        $framework = new UssdFramework([
            'default_menu' => 'main',
        ]);

        // Register menus
        $framework->registerMenu('main', $this->mainMenu());
        $framework->registerMenu('balance', $this->balanceMenu());

        // Handle request and return response
        $response = $framework->handle($request);

        return response($response->formatForNetwork())
            ->header('Content-Type', 'text/plain');
    }

    private function mainMenu(): SimpleMenu
    {
        return new SimpleMenu('Welcome to MyApp', [
            '1' => 'Check Balance',
            '2' => 'Send Money',
            '3' => 'Buy Airtime',
        ], [
            '1' => function ($session, $framework) {
                return $framework->navigateToMenuWithResponse('balance');
            },
        ]);
    }

    private function balanceMenu(): SimpleMenu
    {
        return new SimpleMenu('Your balance is KES 1,500.00', [
            '0' => 'Back to Main Menu',
        ], [
            '0' => function ($session, $framework) {
                return $framework->navigateToMenuWithResponse('main');
            },
        ]);
    }
}

// routes/api.php
Route::post('/ussd', [UssdController::class, 'handle']);

use Moffhub\Ussd\Menus\SimpleMenu;

$menu = new SimpleMenu('Main Menu', [
    '1' => 'Option One',
    '2' => 'Option Two',
    '3' => 'Option Three',
], [
    '1' => function ($session, $framework) {
        return UssdResponse::end('You selected option one!');
    },
]);

use Moffhub\Ussd\Menus\FormMenu;
use Moffhub\Ussd\Helpers\FormField;

$formMenu = new FormMenu('Registration');

$formMenu->addField(new FormField(
    name: 'name',
    prompt: 'Enter your full name:',
    validators: [Validators::you, {$formData['name']}! Registration complete.");
});

use Moffhub\Ussd\Menus\PaginatedMenu;

$menu = new PaginatedMenu('Select Product', $products, [
    'items_per_page' => 5,
    'item_formatter' => fn($item) => $item['name'] . ' - KES ' . $item['price'],
]);

use Moffhub\Ussd\Menus\ConditionalMenu;

$menu = new ConditionalMenu($defaultMenu);

$menu->addCondition(
    fn($session) => $session->getUserData('role') === 'admin',
    $adminMenu
);

$menu->addCondition(
    fn($session) => $session->getUserData('is_premium'),
    $premiumMenu
);

use Moffhub\Ussd\Menus\WizardMenu;

$wizard = new WizardMenu('Money Transfer');

$wizard->addStep('amount', new SimpleMenu('Enter amount:', ['*' => 'Cancel']));
$wizard->addStep('recipient', new SimpleMenu('Enter recipient:', ['*' => 'Cancel']));
$wizard->addStep('confirm', new SimpleMenu('Confirm transfer?', ['1' => 'Yes', '2' => 'No']));

$wizard->setCompletionHandler(function ($session, $data) {
    // Process the transfer
    return UssdResponse::end('Transfer successful!');
});

use Moffhub\Ussd\Builders\MenuBuilder;

$menu = (new MenuBuilder('main_menu'))
    ->title('Welcome')
    ->option('1', 'Check Balance', fn($s, $f) => $f->navigateToMenuWithResponse('balance'))
    ->option('2', 'Send Money')
    ->option('3', 'Exit', fn() => UssdResponse::end('Goodbye!'))
    ->build();



namespace App\Enums;

use Moffhub\Ussd\Interfaces\MenuNameInterface;
use Moffhub\Ussd\Traits\MenuEnumTrait;

enum AppMenu: string implements MenuNameInterface
{
    use MenuEnumTrait;

    case Main = 'main';
    case Balance = 'balance';
    case SendMoney = 'send_money';
    case BuyAirtime = 'buy_airtime';
    case Settings = 'settings';

    public function label(): string
    {
        return match($this) {
            self::Main => 'Main Menu',
            self::Balance => 'Check Balance',
            self::SendMoney => 'Send Money',
            self::BuyAirtime => 'Buy Airtime',
            self::Settings => 'Settings',
        };
    }
}

use App\Enums\AppMenu;

// Register menus with enum
$framework->registerMenu(AppMenu::Main, new SimpleMenu('Welcome', [...]));
$framework->registerMenu(AppMenu::Balance, new SimpleMenu('Balance', [...]));

// Navigate with enum
$framework->navigateToMenu(AppMenu::Balance);
$response = $framework->navigateToMenuWithResponse(AppMenu::SendMoney);

// Check if menu exists
if ($framework->hasMenu(AppMenu::Settings)) {
    // ...
}

// Helper methods from MenuEnumTrait
AppMenu::values();           // ['main', 'balance', 'send_money', ...]
AppMenu::hasValue('main');   // true
AppMenu::fromValue('main');  // AppMenu::Main
AppMenu::toSelectOptions();  // ['main' => 'Main Menu', ...]

use Moffhub\Ussd\Providers\ProviderFactory;

// Auto-detect from request
$provider = ProviderFactory::detect($request);

// Or create a specific provider
$provider = ProviderFactory::create('safaricom');
$provider = ProviderFactory::create('airtel', ['country_code' => '256']);
$provider = ProviderFactory::create('mtn', ['country_code' => '234']);

use Moffhub\Ussd\Providers\ProviderFactory;
use Moffhub\Ussd\Providers\AbstractUssdProvider;

class MyCustomProvider extends AbstractUssdProvider
{
    protected string $name = 'custom';

    public function getPhoneNumber(Request $request): string
    {
        return $request->input('mobile_number');
    }

    // ... implement other methods
}

ProviderFactory::register('custom', MyCustomProvider::class);

use Moffhub\Ussd\DataProviders\ArrayDataProvider;

$provider = new ArrayDataProvider([
    ['id' => 1, 'name' => 'Product A', 'price' => 100],
    ['id' => 2, 'name' => 'Product B', 'price' => 200],
]);

$menu = new PaginatedMenu('Products', $provider);

use Moffhub\Ussd\DataProviders\DatabaseDataProvider;

$provider = new DatabaseDataProvider(Product::class);

// Or with custom query
$provider = new DatabaseDataProvider(Product::class, function () {
    return Product::where('active', true)->orderBy('name');
});

use Moffhub\Ussd\DataProviders\ApiDataProvider;

$provider = new ApiDataProvider(
    'https://api.example.com',
    ['Content-Type: application/json'],
    ['type' => 'bearer', 'token' => 'your-api-token']
);

// In your menu actions
$menu = new SimpleMenu('Menu', ['1' => 'Action'], [
    '1' => function ($session, $framework) {
        // Get session data
        $name = $session->get('name');
        $step = $session->get('step', 0);

        // Set session data
        $session->set('last_action', 'viewed_balance');

        // Form data
        $formData = $session->getFormData();

        // User data (preserved across sessions)
        $userId = $session->getUserData('user_id');

        return UssdResponse::continue("Hello, $name!");
    },
]);

$framework = new UssdFramework([
    'grace_period' => 600, // 10 minutes
    'enable_intelligent_recovery' => true,
    'enable_context_preservation' => true,
]);

$framework = new UssdFramework([
    'security' => [
        'rate_limiting' => true,
    ],
]);

// Configure rate limits with static lists
$rateLimiter = new UssdRateLimiter([
    'max_requests_per_minute' => 10,
    'max_requests_per_hour' => 100,
    'max_requests_per_day' => 500,
    'whitelist' => ['+254700000000'],
    'blacklist' => ['+254999999999'],
]);

use Moffhub\Ussd\Security\UssdRateLimiter;
use Moffhub\Ussd\Security\DatabaseAccessListProvider;

// Enable database-backed lists
$rateLimiter = new UssdRateLimiter([
    'use_database_lists' => true,
    'max_requests_per_minute' => 10,
]);

// Or set a custom provider
$rateLimiter->setAccessListProvider(new DatabaseAccessListProvider([
    'cache_ttl' => 300, // Cache for 5 minutes
    'cache_enabled' => true,
]));

// Manage whitelist/blacklist programmatically
$rateLimiter->addToWhitelist('+254712345678', 'VIP customer', '[email protected]');
$rateLimiter->addToBlacklist('+254999999999', 'Spam detected', 'system', now()->addDays(7));

$rateLimiter->removeFromWhitelist('+254712345678');
$rateLimiter->removeFromBlacklist('+254999999999');

use Moffhub\Ussd\Models\UssdAccessList;

// Add to whitelist with expiration
UssdAccessList::addToWhitelist(
    phoneNumber: '+254712345678',
    reason: 'VIP customer',
    addedBy: auth()->user()->email,
    expiresAt: now()->addMonths(6),
    metadata: ['customer_id' => 123]
);

// Add to blacklist
UssdAccessList::addToBlacklist(
    phoneNumber: '+254999999999',
    reason: 'Abuse detected',
    addedBy: 'system'
);

// Query for your admin panel
$whitelist = UssdAccessList::whitelist()->active()->paginate(20);
$blacklist = UssdAccessList::blacklist()->active()->paginate(20);

// Check status
UssdAccessList::isWhitelisted('+254712345678'); // true
UssdAccessList::isBlacklisted('+254999999999'); // true

// Get all numbers
$whitelistedNumbers = UssdAccessList::getWhitelistedNumbers();
$blacklistedNumbers = UssdAccessList::getBlacklistedNumbers();

use Moffhub\Ussd\Interfaces\AccessListProviderInterface;

class RedisAccessListProvider implements AccessListProviderInterface
{
    public function isWhitelisted(string $phoneNumber): bool
    {
        return Redis::sismember('ussd:whitelist', $phoneNumber);
    }

    public function isBlacklisted(string $phoneNumber): bool
    {
        return Redis::sismember('ussd:blacklist', $phoneNumber);
    }

    // ... implement other methods
}

$rateLimiter->setAccessListProvider(new RedisAccessListProvider());

$framework = new UssdFramework([
    'security' => [
        'input_sanitization' => true,
        'strict_mode' => false, // Set to true to reject suspicious input
    ],
]);

use Moffhub\Ussd\Helpers\Validators;

$field = new FormField(
    name: 'email',
    prompt: 'Enter email:',
    validators: [
        Validators::axLength($max, $message)
Validators::length($min, $max, $message)
Validators::numeric($message)
Validators::phone($message)
Validators::email($message)
Validators::inOptions($options, $message)
Validators::regex($pattern, $message)
Validators::dob($message, $minAge)
Validators::custom($callback, $message)

use Moffhub\Ussd\UssdResponse;

// Continue session
UssdResponse::continue('Select an option:');

// End session
UssdResponse::end('Thank you for using our service!');

// With menu
UssdResponse::menu('Main Menu', ['1' => 'Option 1', '2' => 'Option 2']);

// Form field
UssdResponse::form('Enter your name:', true, $validationError);

// Pagination
UssdResponse::pagination($content, $currentPage, $totalPages, $hasNext, $hasPrevious);

// Progress indicator
UssdResponse::progress('Processing...', $currentStep, $totalSteps);

// Confirmation
UssdResponse::confirmation('Are you sure?');

// Error
UssdResponse::error('Something went wrong', $endSession);

// Success
UssdResponse::success('Operation completed!');

$framework = new UssdFramework([
    // Basic settings
    'session_timeout' => 300,
    'session_prefix' => 'ussd_session_',
    'default_menu' => 'main',
    'sms_length' => 160,

    // Navigation
    'navigation' => [
        'back' => '99',
        'home' => '0',
        'next' => '00',
        'search' => '98',
    ],
    'global_navigation' => ['enabled' => true],

    // Session management
    'grace_period' => 600,
    'enable_session_migration' => true,
    'enable_context_preservation' => true,
    'enable_intelligent_recovery' => true,

    // Security
    'security' => [
        'rate_limiting' => true,
        'input_sanitization' => true,
        'audit_logging' => true,
        'strict_mode' => false,
    ],

    // Analytics
    'analytics' => [
        'enabled' => true,
        'track_user_journey' => true,
        'track_performance' => true,
    ],

    // Caching
    'cache' => [
        'enabled' => true,
        'menu_content_ttl' => 3600,
        'data_provider_ttl' => 600,
    ],

    // Database
    'database' => [
        'enabled' => true,
        'save_sessions' => true,
        'save_analytics' => true,
        'anonymize_phone_numbers' => true,
    ],

    // Provider
    'provider' => [
        'default' => 'generic',
        'auto_detect' => true,
        'country_code' => '254',
        'max_message_length' => 182,
    ],
]);

use Moffhub\Ussd\Facades\Ussd;

$response = Ussd::handle($request);

// Using the helper function
$message = __ussd('errors.invalid_option');
$message = __ussd('navigation.page_info', ['current' => '1', 'total' => '5']);
$message = __ussd('validation.min_length', ['min' => '3'], 'sw');

// Per-session language selection
use Moffhub\Ussd\Services\TranslationService;

$translation = app(TranslationService::class);
$translation->setSessionLocale($session, 'sw');
$message = $translation->translateForSession('navigation.back', $session);

'localization' => [
    'default_locale' => 'en',
    'supported_locales' => ['en', 'sw', 'fr'],
],

'security' => [
    'encrypt_session_data' => true,
    'encrypted_fields' => ['form_data.pin', 'form_data.account_number'],
],

use Moffhub\Ussd\Events\FormSubmitted;

Event::listen(FormSubmitted::class, function (FormSubmitted $event) {
    ProcessRegistration::dispatch($event->formData);
});

// Gateway authentication (IP + signature verification)
Route::post('/ussd', [UssdController::class, 'handle'])->middleware('ussd.auth');

// Per-phone rate limiting
Route::post('/ussd', [UssdController::class, 'handle'])->middleware('ussd.rate-limit');

// Combined
Route::post('/ussd', [UssdController::class, 'handle'])->middleware(['ussd.auth', 'ussd.rate-limit']);
bash
php artisan vendor:publish --provider="Moffhub\Ussd\UssdServiceProvider"
bash
php artisan migrate
bash
php artisan vendor:publish --tag=ussd-lang
bash
php artisan ussd:simulate
bash
# Use a specific phone number
php artisan ussd:simulate --phone=254712345678

# Use a specific provider adapter (safaricom, airtel, mtn, generic)
php artisan ussd:simulate --provider=safaricom

# Use a specific service code
php artisan ussd:simulate --service-code=*456#

# Combine options
php artisan ussd:simulate --phone=254712345678 --provider=safaricom --service-code=*456#