مكتبة دفع الويب لـ PHP
يمكن استخدام WebPush لإرسال رسائل الدفع إلى نقاط النهاية كما هو موضح في بروتوكول Web Push.
يتم بعد ذلك استلام رسالة الدفع هذه بواسطة المتصفح، والذي يمكنه بعد ذلك إنشاء إشعار باستخدام عامل الخدمة وواجهة برمجة تطبيقات الإشعارات.
PHP 8.1+ والامتدادات التالية:
لا يوجد دعم وصيانة لإصدارات PHP الأقدم، ولكن لديك الحرية في استخدام الإصدارات المتوافقة التالية:
v1.x
v2.x
v3.x-v5.x
v6.x
v7.x
v8.x
هذا الملف التمهيدي (README) متوافق فقط مع الإصدار الأحدث. يحتوي كل إصدار من المكتبة على علامة git حيث يمكن قراءة الملف README المطابق.
استخدم الملحن لتنزيل المكتبة وتبعياتها وتثبيتها.
composer require minishlink/web-push
يمكن العثور على مثال كامل للواجهة الأمامية html+JS والواجهة الخلفية php باستخدام web-push-php
هنا: Minishlink/web-push-php-example
<?php
use Minishlink WebPush WebPush ;
use Minishlink WebPush Subscription ;
// store the client - side `PushSubscription` object ( calling ` . toJSON` on it) as - is and then create a WebPush Subscription from it
$ subscription = Subscription:: create ( json_decode ( $ clientSidePushSubscriptionJSON , true ));
// array of notifications
$ notifications = [
[
' subscription ' => $ subscription ,
' payload ' => ' {"message":"Hello World!"} ' ,
], [
// current PushSubscription format ( browsers might change this in the future)
' subscription ' => Subscription:: create ([
" endpoint " => " https://example.com/other/endpoint/of/another/vendor/abcdef... " ,
" keys " => [
' p256dh ' => ' (stringOf88Chars) ' ,
' auth ' => ' (stringOf24Chars) '
],
]),
' payload ' => ' {"message":"Hello World!"} ' ,
], [
// old Firefox PushSubscription format
' subscription ' => Subscription:: create ([
' endpoint ' => ' https://updates.push.services.mozilla.com/push/abc... ' , // Firefox 43 + ,
' publicKey ' => ' BPcMbnWQL5GOYX/5LKZXT6sLmHiMsJSiEvIFvfcDvX7IZ9qqtq68onpTPEYmyxSQNiH7UD/98AUcQ12kBoxz/0s= ' , // base 64 encoded , should be 88 chars
' authToken ' => ' CxVX6QsVToEGEcjfYPqXQw== ' , // base 64 encoded , should be 24 chars
]),
' payload ' => ' hello ! ' ,
], [
// old Chrome PushSubscription format
' subscription ' => Subscription:: create ([
' endpoint ' => ' https://fcm.googleapis.com/fcm/send/abcdef... ' ,
]),
' payload ' => null ,
], [
// old PushSubscription format
' subscription ' => Subscription:: create ([
' endpoint ' => ' https://example.com/other/endpoint/of/another/vendor/abcdef... ' ,
' publicKey ' => ' (stringOf88Chars) ' ,
' authToken ' => ' (stringOf24Chars) ' ,
' contentEncoding ' => ' aesgcm ' , // one of PushManager . supportedContentEncodings
]),
' payload ' => ' {"message":"test"} ' ,
]
];
$ webPush = new WebPush ();
// send multiple notifications with payload
foreach ( $ notifications as $ notification ) {
$ webPush -> queueNotification (
$ notification [ ' subscription ' ],
$ notification [ ' payload ' ] // optional ( defaults null)
);
}
/**
* Check sent results
* @ var MessageSentReport $ report
* /
foreach ( $ webPush -> flush () as $ report ) {
$ endpoint = $ report -> getRequest ()-> getUri ()-> __toString ();
if ( $ report -> isSuccess ()) {
echo " [v] Message sent successfully for subscription { $ endpoint } . " ;
} else {
echo " [x] Message failed to sent for subscription { $ endpoint } : { $ report -> getReason ()}" ;
}
}
/**
* send one notification and flush directly
* @ var MessageSentReport $ report
* /
$ report = $ webPush -> sendOneNotification (
$ notifications [ 0 ][ ' subscription ' ],
$ notifications [ 0 ][ ' payload ' ], // optional ( defaults null)
);
تحتاج المتصفحات إلى التحقق من هويتك. يمكن لمعيار يسمى VAPID مصادقتك لجميع المتصفحات. ستحتاج إلى إنشاء وتوفير مفتاح عام وخاص لخادمك. يجب أن يتم تخزين هذه المفاتيح بشكل آمن ويجب ألا تتغير.
يمكنك تحديد تفاصيل المصادقة الخاصة بك عند إنشاء WebPush. يمكن تمرير المفاتيح مباشرة (مستحسن)، أو يمكنك تحميل ملف PEM أو محتواه:
<?php
use Minishlink WebPush WebPush ;
$ endpoint = ' https://fcm.googleapis.com/fcm/send/abcdef... ' ; // Chrome
$ auth = [
' VAPID ' => [
' subject ' => ' mailto:[email protected] ' , // can be a mailto : or your website address
' publicKey ' => ' ~88 chars ' , // (recommended) uncompressed public key P - 256 encoded in Base64 - URL
' privateKey ' => ' ~44 chars ' , // (recommended) in fact the secret multiplier of the private key encoded in Base64 - URL
' pemFile ' => ' path/to/pem ' , // if you have a PEM file and can link to it on your filesystem
' pem ' => ' pemFileContent ' , // if you have a PEM file and want to hardcode its content
],
];
$ webPush = new WebPush ( $ auth );
$ webPush -> queueNotification (...);
من أجل إنشاء المفتاح العام والسري غير المضغوط، المشفر في Base64، أدخل ما يلي في Linux bash الخاص بك:
$ openssl ecparam -genkey -name prime256v1 -out private_key.pem
$ openssl ec -in private_key.pem -pubout -outform DER | tail -c 65 | base64 | tr -d ' = ' | tr ' /+ ' ' _- ' >> public_key.txt
$ openssl ec -in private_key.pem -outform DER | tail -c +8 | head -c 32 | base64 | tr -d ' = ' | tr ' /+ ' ' _- ' >> private_key.txt
إذا لم تتمكن من الوصول إلى Linux bash، فيمكنك طباعة مخرجات وظيفة createVapidKeys
:
var_dump ( VAPID :: createVapidKeys ()); // store the keys afterwards
من جانب العميل، لا تنس الاشتراك باستخدام المفتاح العام VAPID باعتباره applicationServerKey
: (مصدر urlBase64ToUint8Array
هنا)
serviceWorkerRegistration . pushManager . subscribe ( {
userVisibleOnly : true ,
applicationServerKey : urlBase64ToUint8Array ( vapidPublicKey )
} )
تستخدم رؤوس VAPID رمز ويب JSON (JWT) للتحقق من هويتك. تتضمن حمولة الرمز المميز البروتوكول واسم المضيف لنقطة النهاية المضمنة في الاشتراك والطابع الزمني لانتهاء الصلاحية (عادةً ما بين 12 إلى 24 ساعة)، ويتم توقيعها باستخدام مفتاحك العام والخاص. نظرًا لذلك، فإن الإشعارين المرسلين إلى نفس خدمة الدفع سيستخدمان نفس الرمز المميز، لذا يمكنك إعادة استخدامها لنفس جلسة التدفق لتعزيز الأداء باستخدام:
$ webPush -> setReuseVAPIDHeaders ( true );
يمكن أن يحتوي كل إشعار على وقت محدد للعيش، ودرجة الإلحاح، والموضوع. ينص معيار WebPush على أن urgency
أمر اختياري، لكن أبلغ بعض المستخدمين أن Safari يلقي أخطاء عندما لا يتم تحديده. قد يتم إصلاح هذا في المستقبل. يمكنك تغيير الخيارات الافتراضية باستخدام setDefaultOptions()
أو في المُنشئ:
<?php
use Minishlink WebPush WebPush ;
$ defaultOptions = [
' TTL ' => 300 , // defaults to 4 weeks
' urgency ' => ' normal ' , // protocol defaults to "normal" . ( very - low , low , normal , or high)
' topic ' => ' newEvent ' , // not defined by default . Max . 32 characters from the URL or filename - safe Base64 characters sets
' batchSize ' => 200 , // defaults to 1000
];
// for every notification
$ webPush = new WebPush ([], $ defaultOptions );
$ webPush -> setDefaultOptions ( $ defaultOptions );
// or for one notification
$ webPush -> sendOneNotification ( $ subscription , $ payload , [ ' TTL ' => 5000 ]);
مدة البقاء (TTL، بالثواني) هي المدة التي يتم فيها الاحتفاظ برسالة الدفع بواسطة خدمة الدفع (مثل Mozilla) في حالة عدم إمكانية الوصول إلى متصفح المستخدم بعد (على سبيل المثال، غير متصل). قد ترغب في استخدام وقت طويل جدًا للإشعارات المهمة. مدة البقاء الافتراضية هي 4 أسابيع. ومع ذلك، إذا قمت بإرسال عدة إشعارات غير أساسية، فقم بتعيين TTL على 0: سيتم تسليم إشعار الدفع فقط إذا كان المستخدم متصلاً حاليًا. بالنسبة للحالات الأخرى، يجب عليك استخدام يوم واحد على الأقل إذا كان لدى المستخدمين مناطق زمنية متعددة، وإذا لم يكن لديهم عدة ساعات فستكفي.
يمكن أن تكون درجة الاستعجال إما "منخفضة جدًا" أو "منخفضة" أو "طبيعية" أو "عالية". إذا قام بائع المتصفح بتطبيق هذه الميزة، فسوف يؤدي ذلك إلى توفير عمر البطارية على الأجهزة المحمولة (راجع البروتوكول).
ستجعل هذه السلسلة البائع يظهر للمستخدم فقط الإخطار الأخير لهذا الموضوع (راجع البروتوكول).
إذا قمت بإرسال عشرات الآلاف من الإشعارات في المرة الواحدة، فقد تحصل على فائض في الذاكرة بسبب كيفية استدعاء نقاط النهاية في Guzzle. ولإصلاح هذه المشكلة، يرسل WebPush الإشعارات على دفعات. الحجم الافتراضي هو 1000. اعتمادًا على تكوين الخادم (الذاكرة)، قد ترغب في تقليل هذا الرقم. قم بذلك أثناء إنشاء WebPush أو استدعاء setDefaultOptions
. أو، إذا كنت تريد تخصيص هذا لتدفق معين، فامنحه كمعلمة: $webPush->flush($batchSize)
.
يمكنك رؤية ما يرسله خادم بائع المتصفح مرة أخرى في حالة مواجهة خطأ (انتهاء صلاحية الاشتراك، معلمات خاطئة...).
sendOneNotification()
بإرجاع MessageSentReport
flush()
بإرجاع Generator
مع كائنات MessageSentReport
. لتكرار النتائج، ما عليك سوى تمريرها إلى foreach
. يمكنك أيضًا استخدام iterator_to_array
للتحقق من المحتويات أثناء تصحيح الأخطاء. <?php
/** @var MinishlinkWebPush MessageSentReport $ report * /
foreach ( $ webPush -> flush () as $ report ) {
$ endpoint = $ report -> getEndpoint ();
if ( $ report -> isSuccess ()) {
echo " [v] Message sent successfully for subscription { $ endpoint } . " ;
} else {
echo " [x] Message failed to sent for subscription { $ endpoint } : { $ report -> getReason ()}" ;
// also available ( to get more info )
/** @var Psr Http Message RequestInterface $ requestToPushService * /
$ requestToPushService = $ report -> getRequest ();
/** @var Psr Http Message ResponseInterface $ responseOfPushService * /
$ responseOfPushService = $ report -> getResponse ();
/** @var string $ failReason */
$ failReason = $ report -> getReason ();
/** @var bool $ isTheEndpointWrongOrExpired */
$ isTheEndpointWrongOrExpired = $ report -> isSubscriptionExpired ();
}
}
الرجاء ملاحظة: يمكنك التكرار مرة واحدة فقط عبر الكائن Generator
.
تم إدراج أخطاء Firefox في وثائق الدفع التلقائي.
يتم تشفير الحمولات بواسطة المكتبة. الحد الأقصى لطول الحمولة هو نظريًا 4078 بايت (أو أحرف ASCII). ولأسباب التوافق (المؤرشفة)، يجب أن يكون طول الحمولة النافعة لديك أقل من 3052 بايت.
تقوم المكتبة بتبطين الحمولة بشكل افتراضي. يعد هذا أكثر أمانًا ولكنه يقلل من الأداء لكل من الخادم الخاص بك وجهاز المستخدم الخاص بك.
عندما تقوم بتشفير سلسلة بطول معين، فإن السلسلة الناتجة سيكون لها نفس الطول دائمًا، بغض النظر عن عدد المرات التي تقوم فيها بتشفير السلسلة الأولية. وهذا يمكن أن يجعل المهاجمين يخمنون محتوى الحمولة. من أجل التحايل على هذا، تضيف هذه المكتبة بعض الحشوات الفارغة إلى الحمولة الأولية، بحيث يكون لجميع مدخلات عملية التشفير نفس الطول. بهذه الطريقة، سيكون لجميع مخرجات عملية التشفير أيضًا نفس الطول ولن يتمكن المهاجمون من تخمين محتوى حمولتك.
يستغرق تشفير المزيد من وحدات البايت وقت تشغيل أطول على الخادم الخاص بك، كما يؤدي أيضًا إلى إبطاء جهاز المستخدم أثناء فك التشفير. علاوة على ذلك، فإن إرسال الحزمة واستلامها سيستغرق وقتًا أطول. كما أنها ليست ودية للغاية مع المستخدمين الذين لديهم خطط بيانات محدودة.
يمكنك تخصيص الحشو التلقائي ليناسب احتياجاتك بشكل أفضل.
فيما يلي بعض أفكار الإعدادات:
Encryption::MAX_COMPATIBILITY_PAYLOAD_LENGTH
(2820 بايت) لأغراض التوافق مع Firefox لنظام Android (راجع #108)Encryption::MAX_PAYLOAD_LENGTH
(4078 بايت) لأقصى قدر من الأمانfalse
لتحقيق أقصى قدر من الأداءX
بايت، فقم بتعيينها على X
للحصول على أفضل توازن بين الأمان والأداء. <?php
use Minishlink WebPush WebPush ;
$ webPush = new WebPush ();
$ webPush -> setAutomaticPadding ( false ); // disable automatic padding
$ webPush -> setAutomaticPadding ( 512 ); // enable automatic padding to 512 bytes ( you should make sure that your payload is less than 512 bytes , or else an attacker could guess the content )
$ webPush -> setAutomaticPadding ( true ); // enable automatic padding to default maximum compatibility length
يستخدم WebPush Guzzle. سيستخدم العميل الأنسب الذي يجده، وفي معظم الأحيان سيكون MultiCurl
، والذي يسمح بإرسال إشعارات متعددة بالتوازي.
يمكنك تخصيص خيارات الطلب الافتراضية والمهلة عند إنشاء مثيل WebPush:
<?php
use Minishlink WebPush WebPush ;
$ timeout = 20 ; // seconds
$ clientOptions = [
GuzzleHttp RequestOptions:: ALLOW_REDIRECTS => false ,
]; // see GuzzleHttp RequestOptions
$ webPush = new WebPush ([], [], $ timeout , $ clientOptions );
ما يلي متاح:
لا تتردد في إضافة بنفسك!
يتم تشفير الحمولة وفقًا لمعيار تشفير الرسائل لـ Web Push، وذلك باستخدام المفتاح العام للمستخدم وسر المصادقة الذي يمكنك الحصول عليه باتباع مواصفات Web Push API.
داخليًا، يستخدم WebPush إطار عمل WebToken وOpenSSL للتعامل مع إنشاء مفاتيح التشفير وتشفيرها.
وهنا بعض الأفكار:
defaultOptions
أو كمعلمة flush()
)flushPooled()
بدلاً من flush()
. يستخدم الأول الطلبات المتزامنة، مما يؤدي إلى تسريع العملية ومضاعفة سرعة الطلبات غالبًا.التثبيت الخاص بك يفتقر إلى بعض الشهادات.
php.ini
الخاص بك: بعد [curl]
، اكتب curl.cainfo = /path/to/cacert.pem
.يمكنك أيضًا فرض استخدام عميل دون التحقق من الأقران.
تأكد من طلب أداة التحميل التلقائي للملحن.
require __DIR__ . ' /path/to/vendor/autoload.php ' ;
تأكد من أن حقول قاعدة البيانات كبيرة بما يكفي لطول البيانات التي تقوم بتخزينها (#233). بالنسبة لنقطة النهاية، أبلغ المستخدمون أن طول عنوان URL لا يتجاوز 500 حرف، ولكن هذا يمكن أن يتطور بحيث يمكنك ضبطه على الحد الأقصى البالغ 2048 حرفًا لمعظم المتصفحات.
راجع العدد رقم 58.
هذه الخدمة لم تعد موجودة. وقد تم استبداله بـ Firebase Cloud Messaging (FCM) من Google في 29 مايو 2019.
لا تدعم هذه المكتبة خدمة Firebase Cloud Messaging (FCM). تستخدم اشتراكات Chrome القديمة (قبل عام 2018 وVAPID) بروتوكول Legacy HTTP بواسطة Firebase Cloud Messaging (FCM) الذي تم إيقافه منذ عام 2023 وسيتوقف عن العمل في يونيو 2024. تمت إزالة الدعم لهذا الاشتراك القديم.
من فضلك لا تخلط بين بروتوكول Legacy HTTP وWeb Push مع VAPID يستخدمان عنوان URL المتطابق لنقطة النهاية:
https://fcm.googleapis.com/fcm/send
سيظل Web Push مع VAPID متاحًا على عنوان URL هذا. لا يوجد أي إجراء آخر مطلوب في الوقت الحالي.
لا يسمح بائعو المتصفح بإرسال البيانات باستخدام Push API دون إنشاء إشعار. استخدم بعض واجهات برمجة التطبيقات البديلة مثل WebSocket/WebTransport أو مزامنة الخلفية.
WebPush مخصص لتطبيقات الويب. أنت بحاجة إلى شيء مثل RMSPushNotificationsBundle (Symfony).
هذه المكتبة مستوحاة من مكتبة Node.js web-push-libs/web-push.
server.js
: يجب استبداله بكود خادم PHP الخاص بك مع هذه المكتبة)معهد ماساتشوستس للتكنولوجيا