فهرست مطالب (8)
هر نسخهٔ تازهٔ PHP معمولاً با فهرستی از قابلیتهای جذاب معرفی میشود و PHP 8.6 هم از این قاعده مستثنا نیست. ولی این بار مهمترین تغییر برای خیلی از فروشگاههای ایرانی در فهرست قابلیتها نیست؛ در فهرست «تغییرات ناسازگار» است، در قالب سه خط که پیشفرضهای سشن را عوض میکنند.
PHP 8.6 طبق برنامهٔ رسمی ۱۹ نوامبر ۲۰۲۶ منتشر میشود؛ یعنی حدود سه هفتهٔ دیگر. اگر فروشگاه یا افزونهای دارید که با درگاه بانکی کار میکند، این یادداشت را تا آخر بخوانید.
سه پیشفرض تازه برای سشن
پیشنهاد «پیشفرضهای امن برای پیکربندی سشن» در فهرست پیشنهادهای رسمی PHP با رأی تقریباً یکپارچه پذیرفته شد. از PHP 8.6، این سه تنظیم بهطور پیشفرض روشناند:
- **
session.use_strict_mode = 1:** PHP دیگر شناسهٔ سشنی را که خودش نساخته نمیپذیرد. - **
session.cookie_httponly = 1:** جاوااسکریپت دیگر نمیتواند کوکی سشن را ازdocument.cookieبخواند. - **
session.cookie_samesite = Lax:** مرورگر کوکی سشن را در درخواستهای POST که از سایت دیگری میآیند، نمیفرستد.
هر سه از نظر امنیتی کاملاً درستاند. دو مورد اول در عمل برای بیشتر سایتها بیدردسرند. اما سومی دقیقاً به جایی میخورد که فروشگاههای ایرانی زیاد از آن استفاده میکنند.
مشکل کجاست: بازگشت از بانک
در بسیاری از درگاههای بانکی، مسیر پرداخت این شکلی است: مشتری در سایت شما روی «پرداخت» میزند، به صفحهٔ بانک میرود، پرداخت را انجام میدهد و بانک او را با یک فرم POST به آدرس بازگشت سایت شما برمیگرداند.
از دید مرورگر، این درخواست POST از دامنهٔ بانک به دامنهٔ شما رفته است؛ یعنی یک درخواست POST بینسایتی. با پیشفرض تازهٔ SameSite=Lax، مرورگر کوکی سشن PHP را همراه این درخواست نمیفرستد.

حالا فرض کنید افزونهٔ درگاه شما شمارهٔ سفارش یا مبلغ را پیش از رفتن به بانک در $_SESSION گذاشته باشد و در بازگشت، همان را از سشن بخواند. روی PHP 8.6 با تنظیمات پیشفرض، سشن در این لحظه خالی است. نتیجه میتواند سفارشی باشد که پولش کم شده ولی در سایت «پرداختنشده» میماند؛ یعنی دقیقاً همان تیکتی که هیچ فروشندهای دوست ندارد ببیند.
یک نکتهٔ مهم: خود هستهٔ وردپرس از سشن PHP استفاده نمیکند و ووکامرس هم سشن خودش را با کوکی و دیتابیس مدیریت میکند. پس این مشکل مستقیماً مربوط به افزونهها، قالبها و کدهای سفارشی است که خودشان session_start() را صدا میزنند. متأسفانه در افزونههای درگاه پرداخت ایرانی، این الگو کم نیست.
اول: بفهمید درگیر هستید یا نه
یک جستوجوی ساده در پوشهٔ افزونهها و قالب کافی است:
grep -rnE "session_start|\$_SESSION" wp-content/plugins wp-content/themes \
--include=*.php | grep -v "/vendor/"
هر نتیجهای که در افزونهٔ درگاه پرداخت یا مسیر بازگشت از بانک باشد، باید بررسی شود.
دوم: راهحل درست
راهحل اصلی این است که مسیر بازگشت اصلاً به سشن تکیه نکند. این الگو هم با PHP 8.6 کار میکند و هم امنتر است:
- شناسهٔ سفارش را در خود آدرس بازگشت بگذارید. ووکامرس برای هر سفارش یک کلید تصادفی دارد (
order_key). آدرس بازگشت را با شناسهٔ سفارش و همین کلید بسازید. - در بازگشت، سفارش را از روی آدرس پیدا کنید، کلید را با
hash_equals()مقایسه کنید و مبلغ را از خود سفارش بخوانید، نه از چیزی که از بیرون آمده. - پرداخت را همیشه با سرویس تأیید (verify) بانک نهایی کنید. هیچوقت فقط به پارامترهایی که بانک در بازگشت فرستاده اعتماد نکنید.
// Building the return URL before redirecting to the bank.
$callback = add_query_arg(
array(
'order' => $order->get_id(),
'key' => $order->get_order_key(),
),
WC()->api_request_url( 'my_gateway' )
);
// On return: find the order from the URL, not from $_SESSION.
$order = wc_get_order( absint( $_GET['order'] ?? 0 ) );
if ( ! $order || ! hash_equals( $order->get_order_key(), (string) ( $_GET['key'] ?? '' ) ) ) {
wp_die( esc_html__( 'Invalid payment return.', 'my-gateway' ), 400 );
}
// Then verify the transaction with the bank's API using $order->get_total().
اگر کد افزونه دست شما نیست، برای سازندهاش تیکت بزنید و صریحاً بپرسید با session.cookie_samesite=Lax تست کرده یا نه.
راهحل موقت، با احتیاط
اگر تا انتشار PHP 8.6 فرصت اصلاح ندارید، میتوانید پیشفرض قدیمی را برگردانید: session.cookie_samesite را در php.ini خالی بگذارید، یا فقط برای همان مسیر با session_set_cookie_params() مقدار None و secure بدهید. ولی یادتان باشد این یعنی کنار گذاشتن یک لایهٔ محافظت در برابر حملات CSRF. این را مُسکن ببینید، نه درمان.
قابلیتهای تازهای که ارزش دیدن دارند
PHP 8.6 فقط دربارهٔ سشن نیست. چند قابلیت هم دارد که کد روزمره را تمیزتر میکند:
- کاربرد جزئی تابع (Partial Function Application): میتوانید بخشی از آرگومانها را از قبل پر کنید و بقیه را با
?خالی بگذارید. این قابلیت با عملگر pipe در PHP 8.5 ترکیب خیلی خوبی دارد، چون pipe فقط تابعهای یکآرگومانی را میپذیرد. - **
clamp():** مقداری را بین یک حداقل و حداکثر نگه میدارد؛ مثلاً درصد تخفیفی که نباید از صفر کمتر یا از صد بیشتر شود. - **کلاس
Time\Duration:** برای نمایش بازههای زمانی، با متدهایی برای جمع و ضرب و امکان مقایسهٔ مستقیم.
$slug = str_replace( ' ', '-', ? ); // partial application
echo $slug( 'Hello World' ); // Hello-World
echo 'Hello World' |> $slug; // works with the pipe operator too
$percent = clamp( $discount, min: 0, max: 100 );
جمعبندی
PHP 8.6 نسخهٔ پرسروصدایی نیست، ولی تغییر پیشفرضهای سشنش از آن تغییرهایی است که بیصدا چیزی را خراب میکنند. خبر خوب این است که هنوز سه هفته وقت دارید. یک بار کد درگاه پرداختتان را بگردید، اگر به $_SESSION تکیه دارد اصلاحش کنید، و پیش از ارتقای سرور، یک پرداخت آزمایشی را روی PHP 8.6 از اول تا آخر انجام دهید.
منابع
$ ./request_review
همین مشکل را در فروشگاه خودتان دارید؟
توسعهدهنده ارشد WordPress و WooCommerce برای معماری، اتصال سیستمها و حل مسائل پیچیده production.
درخواست بررسی فنی
## دیدگاهها