ارسال پیامک از فرم المنتور: شماره و متن را بازدیدکننده هم می‌تواند عوض کند

کارتی با دو مقدار خط‌خورده، شماره ۰۹۱۲۱۲۳۴۵۶۷ و متن «سفارش شما ثبت شد»، و مقدارهای تازه‌ای که جایشان نشسته‌اند: شماره ۰۹۳۵۰۰۰۰۰۰۰ و متن any text the visitor writes
محصولات زیر برای شماست...
جدیدترین مقالات
دسترسی سریع
فهرست محتوا

ارسال پیامک از فرم المنتور را با اکشن وب‌هوک (Webhook) آزمودیم، روی وردپرس ۷٫۱٫۴ فارسی با المنتور پرو ۴٫۳٫۲ (فایلی که فروشگاه می‌فروشد). وب‌هوک فرمی را به‌جای پنل پیامک به سروری کوچک وصل کردیم که هر درخواست رسیده را ثبت می‌کند؛ روشش همان است که برای دیجیتس به کار بردیم و از این‌جا سرور نمونه می‌نامیمش. پیامکی به هیچ گوشی نرفت و با هیچ پنل واقعی کار نکردیم.

المنتور ۴ دو فرم دارد: ویجت Form در گروه پرو و «فرم اتمی» (Atomic Form). آزمایش‌های این نوشته روی Form است و فرم اتمی در بخش آخر جدا آمده، چون رفتارش فرق دارد. وب‌هوک Form برچسب هر فیلد را نام پارامتر می‌کند، پس با نام‌های مستندات کاوه‌نگار همان سه پارامتر را می‌فرستد. اما شماره، متن و فرستنده از مرورگر بازدیدکننده می‌آیند و او می‌تواند عوضشان کند. ویجت Form فقط پاسخ ۲۰۰ را موفقیت می‌داند و فیلد تلفنش ارقام فارسی را رد می‌کند.

کد بخش «درخواست پیامک را در خود وردپرس بسازیم» متن و فرستنده را دیگر از مرورگر نمی‌گیرد و ارقام فارسی را درست می‌کند. برای پاسخ ۲۰۰ با خطا در بدنه تابعی روی پاسخ پنل لازم است؛ آن را در پایان همان بخش توضیح داده‌ایم و کدش را چاپ نکرده‌ایم.

ملی‌پیامک برای پنل خودش افزونه‌ای رایگان برای المنتور دارد که المنتور پرو می‌خواهد؛ آن را آزمایش نکردیم. این نوشته برای پنلی است که چنین افزونه‌ای ندارد، یا برای کسی که افزونه اضافه نمی‌خواهد.

برچسب فیلد نام پارامتر می‌شود، نه شناسه فیلد

اکشن وب‌هوک در بخش Actions After Submit فرم است و فقط دو تنظیم دارد: یک نشانی و گزینه Advanced Data (شکل ۱، سمت راست). ویجت Form و این اکشن را فقط در بسته پرو یافتیم؛ نوشته تفاوت رایگان و پرو هم وب‌هوک را از کارهای فرم پرو می‌شمارد. در پوشه افزونه رایگان ۴٫۳٫۵ ویجت Form نبود؛ «فرم اتمی» در آن بدون پرو فقط جایگزینی برای معرفی پرو است. افزونه‌های دیگر را نگشتیم.

سه ستون: فهرست فیلدهای فرم با سه برچسب Receptor و Message و Sender، درخواستی که سرور نمونه با همین سه نام به‌اضافه Form_Id و Form_Name گرفت، و بخش Webhook با نشانی و گزینه Advanced Data خاموش
سمت چپ برچسب‌های فرمی که در بخش بعد می‌آید، وسط درخواستی که از آن رسید، و سمت راست بخش Webhook آن.

فرمی با برچسب‌های Name، Phone و Message (شناسه‌ها name، phone و message) را با مقدارهای Ali، 09121234567 و salam فرستادیم. سرور نمونه این را گرفت:

CODE
وردپرس نیاز
POST /
Content-Type: application/x-www-form-urlencoded

Name=Ali&Phone=09121234567&Message=salam&form_id=f9d53f76&form_name=Contact

نام پارامترها همان برچسب‌هاست و بعدشان form_id و form_name اضافه می‌شود. با برچسب فارسی «شماره موبایل» نام پارامتر هم فارسی است و با رمزگذاری URL می‌رسد. فرم این آزمایش‌ها اکشن Email نداشت (فقط Webhook و Collect Submissions)؛ فرم تازه با Email شروع می‌شود و با آن شش پارامتر دیگر هم می‌رود: Date، Time، Page URL، User Agent، Remote IP و Powered by.

اگر Advanced Data را روشن کنید JSON نمی‌گیرید: درخواست باز هم فرمی است، با ۲۰ پارامتر تودرتو برای فرم سه‌فیلدی ما. در تنظیم‌های این اکشن جایی برای روش ارسال، هدر یا قالب JSON نیست؛ با فیلتری که در بخش «درخواست پیامک را در خود وردپرس بسازیم» می‌آید هدر و بدنه JSON را عوض کردیم، و روش ارسال را عوض نکردیم.

سرور نمونه روی آدرسی خصوصی در شبکه داکر است و این بر آزمایش اثر گذاشت. اکشن از تابع امن درخواست وردپرس (wp_safe_remote_post) استفاده می‌کند و آن تابع آدرس خصوصی را رد می‌کند، مگر فیلتر http_request_host_is_external اجازه بدهد؛ پورت‌های مجاز هم ۸۰ و ۴۴۳ و ۸۰۸۰ است (مستندات وردپرس). بدون اجازه هیچ درخواستی نرسید و بازدیدکننده فقط «Your submission failed because of an error.» دید.

از این به بعد همه اجراها با اجازه برای همین یک میزبان بود. فرم‌ها را با اسکریپت ساختیم و یکی را در ویرایشگر المنتور هم ذخیره کردیم؛ درخواستش همان ماند.

با نام‌های کاوه‌نگار، همان وب‌هوک پارامترهایی با نام مستندات می‌فرستد

مستندات کاوه‌نگار کلید API را در مسیر نشانی ارسال می‌گذارد (api.kavenegar.com/v1/API-KEY/sms/send.json، با https در ابتدا) و سه پارامتر می‌خواهد: receptor، message (که باید با رمزگذاری URL برسد) و sender (اختیاری)، به روش GET یا POST.

فرمی با سه فیلد به همین نام‌ها ساختیم: receptor از نوع Tel، و message و sender از نوع Hidden با مقدار پیش‌فرض. گزینه Label فرم را خاموش کردیم تا برچسب‌ها دیده نشوند و در placeholder فیلد شماره عبارت «شماره موبایل» را گذاشتیم. نشانی وب‌هوک نشانی ارسال کاوه‌نگار بود، با میزبان sms (نام سرور نمونه) و کلید ساختگی KEY0123. سرور نمونه این را گرفت، با بدنه‌ای که این‌جا رمزگشایی شده:

CODE
وردپرس نیاز
POST /v1/KEY0123/sms/send.json
receptor = 09121234567
message = سفارش شما ثبت شد
sender = 10001234
form_id = f2b8fc25
form_name = SMS

سه نام مستندات کاوه‌نگار را دارد و دو پارامتر اضافه؛ نمی‌دانیم پنل با آن دو چه می‌کند، چون به پنل واقعی نفرستادیم. ملی‌پیامک در نمونه REST خود نام کاربری و رمز را در بدنه می‌خواهد (username، password، to، from و text). اگر نام کاربری و رمز را فیلد پنهان کنید، مثل مقدار sender در صفحه دیده می‌شوند.

فیلد پنهان را هر کسی که صفحه را باز کند می‌تواند عوض کند

مقدار فرستنده، 10001234، در HTML صفحه چاپ شده بود. کلید API در نشانی وب‌هوک نه در HTML بود و نه در JSON صفحه که REST می‌دهد. برای دیدن اینکه مقدار پنهان چقدر قابل اعتماد است، با یک درخواست دستی به admin-ajax.php (نه با کلیک روی دکمه) شماره‌ای دیگر، متنی دیگر و فرستنده‌ای دیگر فرستادیم. سرور نمونه این را گرفت:

CODE
وردپرس نیاز
POST /v1/KEY0123/sms/send.json
receptor = 09350000000,09360000000
message = any text the visitor writes
sender = 10009999
form_id = f2b8fc25
form_name = SMS

هر سه مقدار همان‌طور رسید، با دو شماره در receptor (مستندات کاوه‌نگار اجازه می‌دهد شماره‌ها با ویرگول بیایند). اگر پنل واقعی پشت این آدرس بود، هر کدام از این درخواست‌ها پیامکی می‌خواست با شماره و متنی که شما تعیین نکرده‌اید. ده ارسال پشت‌سرهم با یک اسکریپت هم ۱٫۸ ثانیه طول کشید و ده درخواست رسید؛ فرم در این ده بار محدودیتی نگذاشت. برای فرم خودتان منبع صفحه را باز کنید و دنبال فیلدهای input با نوع hidden بگردید: هر مقداری که آن‌جا هست بازدیدکننده هم می‌بیند و می‌تواند عوض کند.

ویجت Form فقط پاسخ ۲۰۰ را موفقیت می‌داند

کد اکشن وب‌هوک ویجت Form (فایل webhook.php در بسته پرو) بعد از ارسال، کد پاسخ را فقط با ۲۰۰ مقایسه می‌کند. سرور نمونه را طوری تنظیم کردیم که هر بار پاسخ دیگری بدهد:

پاسخ سرور نمونهآنچه بازدیدکننده دیددرخواست به سرور نمونه رسید؟
۲۰۰موفقبله
۵۰۰خطابله
۲۰۱خطابله
۲۰۰ با کلمه error در بدنه (بدنه‌ای که خودمان ساختیم)موفقبله
۲۰۰ بعد از ۸ ثانیهخطا، بعد از ۵٫۰۸ ثانیهبله

مهلت ۵ ثانیه پیش‌فرض خود وردپرس است. در ردیف آخر درخواست رسیده بود و سرور نمونه ۸ ثانیه بعد جواب داد، ولی بازدیدکننده بعد از ۵٫۰۸ ثانیه خطا دید و می‌تواند دوباره بفرستد. کاوه‌نگار طبق مستنداتش نتیجه را در کد HTTP هم برمی‌گرداند (مثلاً ۴۱۸ برای کمبود اعتبار)، پس برای کاوه‌نگار ردیف چهارم را انتظار نداریم؛ بدنه آن ردیف را خودمان ساختیم و پاسخ ملی‌پیامک را نخوانده‌ایم.

شکل ۲ جدول Submissions را بعد از چهار ارسال نشان می‌دهد: ردیف‌های جدول بالا، به‌جز ۲۰۱ که در این اجرا نبود.

جدول Submissions المنتور با چهار ورودی: پاسخ ۲۰۰ بعد از ۸ ثانیه و پاسخ ۵۰۰ با علامت هشدار قرمز در ستون Actions Status، و پاسخ ۲۰۰ با خطا در بدنه و پاسخ ۲۰۰ با تیک سبز
ستون Actions Status بعد از چهار ارسال، با پاسخی که سرور نمونه برای هر ردیف داده بود.

ورودی هر چهار ارسال ذخیره شد، چون اکشن Collect Submissions روشن بود. ستون Actions Status برای پاسخ ۲۰۰ با خطا در بدنه سبز است و برای ۲۰۰ بعد از ۸ ثانیه قرمز؛ سبز یعنی المنتور ۲۰۰ گرفت، نه اینکه پیامک رفت.

فیلد تلفن ویجت Form ارقام فارسی را رد می‌کند

فیلد Tel ویجت Form در کد خود الگویی دارد که از میان ارقام فقط لاتین را می‌پذیرد، و سرور هم همان را وارسی می‌کند. در کروم ۱۵۵ مرورگر جلوی ارسال شماره ۰۹۱۲۱۲۳۴۵۶۷ را با ارقام فارسی نگرفت؛ سرور رد کرد و زیر فیلد نوشت «The field accepts only numbers and phone characters (#, -, *, etc).» (شکل ۳، سمت راست). پیام‌های پرو در فایل فروشگاه انگلیسی است و پوشه زبان ندارد.

همین را در مقایسه فرم‌سازها هم دیده بودیم. در فیلد Text همان ارقام فارسی بدون تغییر به سرور نمونه رسید. مستندات کاوه‌نگار چهار قالب شماره را فهرست کرده و هر چهار با ارقام لاتین نوشته شده است.

دو فرم با همان فیلدها: در سمت راست فیلد Tel که ارقام فارسی را با دو پیام خطای انگلیسی رد کرده، و در سمت چپ فیلد Text با کد بعد از ارسال موفق، با پیام فارسی و شماره‌ای که سرور نمونه با ارقام لاتین گرفت
همان شماره با ارقام فارسی در دو فرم؛ در سمت چپ فرم بعد از ارسال خالی شده است.

درخواست پیامک را در خود وردپرس بسازیم تا مرورگر فقط شماره را بدهد

تنظیم فرم و کد

تنظیم‌های فرم sms-form این بود:

  1. نام فرم (Form Name): sms-form.
  2. دو فیلد از نوع Text، «نام» و «شماره موبایل»، با شناسه phone برای دومی (تب Advanced فیلد، کادر ID).
  3. اکشن‌ها: Webhook و Collect Submissions (بدون Email).
  4. بخش Webhook: در آزمایش ما نشانی سرور نمونه، و برای پنل واقعی api.kavenegar.com/v1/API-KEY/sms/send.json با https در ابتدا و کلید خودتان؛ Advanced Data خاموش.
  5. پیام‌های سفارشی (Custom Messages) روشن، با متن فارسی.

فایل sms-bridge.php را در پوشه‌ای مثل wp-content/plugins/sms-bridge بگذارید و از صفحه افزونه‌ها فعالش کنید؛ ما آن را در همین پوشه گذاشتیم و فعال کردیم. ارقام فارسی و شماره ناقص را در functions.php قالب فرزند هم آزمودیم و نتیجه یکی بود (آن‌جا چهار خط اول، یعنی آغاز php و توضیح Plugin Name، را نگذارید). قسمت اول، پیش از پذیرش فرم:

PHP
وردپرس نیاز
<?php
/**
 * Plugin Name: SMS from the contact form
 */

// قبل از پذیرش فرم: ارقام لاتین، شماره‌ای که با 09 شروع می‌شود، یک پیامک به هر شماره در ده دقیقه.
add_action( 'elementor_pro/forms/validation', function ( $record, $ajax_handler ) {
	if ( 'sms-form' !== $record->get_form_settings( 'form_name' ) ) {
		return;
	}
	$phone = preg_replace_callback( '/[\x{0660}-\x{0669}\x{06F0}-\x{06F9}]/u', function ( $m ) {
		return (string) ( mb_ord( $m[0] ) & 15 );
	}, $record->get( 'fields' )['phone']['value'] );

	if ( ! preg_match( '/^09\d{9}$/', $phone ) ) {
		$ajax_handler->add_error( 'phone', 'شماره موبایل را مثل ۰۹۱۲۳۴۵۶۷۸۹ بنویسید.' );
	} elseif ( get_transient( 'sms_' . $phone ) ) {
		$ajax_handler->add_error( 'phone', 'برای این شماره تازه پیامک فرستاده‌ایم. چند دقیقه بعد دوباره امتحان کنید.' );
	} else {
		$record->update_field( 'phone', 'value', $phone );
	}
}, 10, 2 );

این قسمت ارقام را لاتین می‌کند و شماره‌ای را که با ۰۹ شروع نشود یا یازده رقم نباشد، یا ده دقیقه پیش پیامک گرفته باشد، با پیام فارسی رد می‌کند. قسمت دوم، همان فایل، خود درخواست را در وردپرس می‌سازد:

PHP
وردپرس نیاز
// خود درخواست: در خود وردپرس ساخته می‌شود و مرورگر فقط شماره را تعیین می‌کند.
add_filter( 'elementor_pro/forms/webhooks/request_args', function ( $args, $record ) {
	if ( 'sms-form' === $record->get_form_settings( 'form_name' ) ) {
		$phone = $record->get( 'fields' )['phone']['value'];
		set_transient( 'sms_' . $phone, 1, 10 * MINUTE_IN_SECONDS );
		$args['timeout'] = 15;
		$args['body']    = array(
			'receptor' => $phone,
			'message'  => 'درخواست شما ثبت شد. به‌زودی با شما تماس می‌گیریم.',
			'sender'   => '10001234',
		);
	}
	return $args;
}, 10, 2 );

متن، فرستنده و مهلت ۱۵ ثانیه از خود وردپرس می‌آیند، و فیلدهای اضافه‌ای که کسی دستی بفرستد دور ریخته می‌شود. شماره فرستنده نمونه است؛ خط خودتان را بنویسید. فیلتر elementor_pro/forms/webhooks/request_args در صفحه هوک‌های فرم المنتور فهرست نشده، ولی در کد اکشن پرو ۴٫۳٫۲ هست.

نتیجه اجرا، و تغییر برای ملی‌پیامک، هدر و JSON

نتیجه روی سرور نمونه؛ ارقام فارسی را در کروم تایپ کردیم (شکل ۳، سمت چپ) و بقیه درخواست‌ها را اسکریپت فرستاد:

  • شماره ۰۹۱۲۱۲۳۴۵۶۷ با ارقام فارسی نوشته شد و سرور نمونه receptor=09121234567 را با متن و فرستنده ثابت گرفت.
  • شماره ناقص ۰۹۱۲ با پیام فارسی رد شد؛ شماره‌ای که همین حالا پیامک گرفته بود هم همین‌طور. در هر دو هیچ درخواستی به سرور نمونه نرفت.
  • با message، sender و receptor دستی در درخواست، سرور نمونه فقط متن و فرستنده ثابت و شماره خود فرم را گرفت.
  • پنلی که ۸ ثانیه معطل کرد، با مهلت ۱۵ ثانیه موفق شد.
  • پاسخ ۵۰۰ هنوز خطا می‌دهد؛ و چون قفل ده‌دقیقه‌ای پیش از ارسال گذاشته می‌شود، ارسال ناموفق هم نوبت آن شماره را مصرف می‌کند.

برای ملی‌پیامک نشانی وب‌هوک rest.payamak-panel.com/api/SendSMS/SendSMS است (با https در ابتدا؛ نشانی نمونه REST مستنداتش) و آرایه این می‌شود. آن را هم با همین کد روی سرور نمونه فرستادیم و نام‌ها را همان‌طور گرفت؛ به ملی‌پیامک نفرستادیم. نام کاربری، رمز و شماره فرستنده در آن نمونه‌اند:

PHP
وردپرس نیاز
$args['body'] = array(
	'username' => 'USERNAME',
	'password' => 'API-KEY',
	'to'       => $phone,
	'from'     => '5000123',
	'text'     => 'درخواست شما ثبت شد. به‌زودی با شما تماس می‌گیریم.',
);

تابعی روی elementor_pro/forms/webhooks/response می‌تواند بدنه پاسخ را بخواند و Exception بیندازد تا ۲۰۰ با خطا هم شکست حساب شود؛ این را با بدنه ساختگی سرور نمونه آزمودیم. نام و جای خطا را از مستندات پنل خودتان بردارید.

پنلی که هدر یا JSON می‌خواهد هم با همین فیلتر درست می‌شود. این سه خط را با نام‌ها و کلید نمونه روی سرور نمونه اجرا کردیم و هدر و بدنه JSON همان‌طور رسید:

PHP
وردپرس نیاز
$args['headers']['Authorization'] = 'Bearer API-KEY';
$args['headers']['Content-Type']  = 'application/json';
$args['body']                     = wp_json_encode( array( 'to' => '09121234567', 'text' => 'test' ) );

کلید API هنوز در کادر نشانی وب‌هوک است. کسی که شماره‌های زیادی دارد از محدودیت یک پیامک به هر شماره می‌گذرد؛ کپچا و فرم چندمرحله‌ای را آزمایش نکردیم. اگر نمی‌خواهید خودتان کد بگذارید، می‌توانید آن را در فرم سفارش (بخش توسعه) بسپارید.

فرم اتمی: پاسخ ۵۰۰ پنل را هم به بازدیدکننده موفق نشان داد

«فرم اتمی» در پنل المنتور ۴ جدا از Form است و وب‌هوکش کد جدایی در همین بسته پرو دارد. با فرمی با دو فیلد (نام، و شماره موبایل از نوع tel) و فقط اکشن Webhook، روی همان سرور نمونه و از مرورگر این‌ها را دیدیم:

  • برچسب فیلدها باز هم نام پارامتر می‌شود. بعدش form_id (شناسه عنصر)، form_name، post_id، site_url و timestamp می‌آید و هدر User-Agent برابر «Elementor Pro Atomic Forms/4.3.2» است.
  • ۲۰۱ و ۲۰۰ با خطا در بدنه موفق شمرده شد؛ کد پرو هر پاسخ با کد ۲۰۰ تا ۲۹۹ را موفق می‌داند.
  • با پاسخ ۵۰۰ و با پنلی که ۸ ثانیه معطل کرد (مهلت ۵ ثانیه گذشت)، در JSON جوابی که صفحه از وردپرس گرفت اکشن Webhook با وضعیت failed آمده بود، ولی صفحه به بازدیدکننده پیام موفقیت را نشان داد.
  • فیلد تلفن الگو ندارد و ارقام فارسی بدون تغییر رسید.

فیلتر درخواست این فرم نام دیگری دارد (elementor_pro/atomic_forms/webhooks/request_args) و آرگومان‌های دیگری می‌گیرد؛ کد این نوشته روی آن اجرا نمی‌شود و نسخه‌ای برایش ننوشتیم.

پرسش‌های متداول

اکشن وب‌هوک المنتور را بدون المنتور پرو هم می‌شود داشت؟

در آزمایش ما ویجت Form و اکشن وب‌هوکش فقط در بسته پرو بود؛ در پوشه افزونه رایگان ۴٫۳٫۵ ویجت Form نبود (فرم اتمی هم بدون پرو فقط جایگزینی برای معرفی پرو است)، و افزونه‌های دیگر را نگشتیم. وب‌هوک «فرم اتمی» جدا است و کدش هم در پرو است.

چرا فرم المنتور شماره‌ای را که با ارقام فارسی نوشته‌ام رد می‌کند؟

فیلد Tel ویجت Form الگویی دارد که از میان ارقام فقط لاتین را می‌پذیرد و سرور هم همان را وارسی می‌کند؛ در فایل فروشگاه پیام خطا انگلیسی بود. فیلد Text ارقام فارسی را قبول می‌کند و کدی که درخواست پیامک را در وردپرس می‌سازد آن‌ها را پیش از ارسال به پنل لاتین می‌کند.

چرا فرم موفق نشان داد ولی پیامک نرسید؟

ویجت Form فقط پاسخ ۲۰۰ را موفقیت می‌داند؛ در آزمایش ما پاسخ ۲۰۰ با خطا در بدنه هم «موفق» نشان داده شد و در Submissions سبز بود. فرم اتمی حتی پاسخ ۵۰۰ را هم به بازدیدکننده موفق نشان داد. پاسخ پنل را در مستنداتش بخوانید.

بازدیدکننده می‌تواند شماره و متن پیامک را عوض کند؟

اگر شماره، متن و فرستنده فیلدهای ویجت Form باشند، بله: با یک درخواست دستی هر سه را عوض کردیم و سرور نمونه همان‌ها را گرفت. کدی که درخواست پیامک را در وردپرس می‌سازد متن و فرستنده را از خود وردپرس می‌گیرد.

کلید API پنل در صفحه برای بازدیدکننده دیده می‌شود؟

در آزمایش ما نشانی وب‌هوک با کلید نه در HTML صفحه بود و نه در JSON صفحه که REST می‌دهد؛ ولی مقدار فیلدهای پنهان در HTML چاپ شده بود.

کدی که درخواست پیامک را در وردپرس می‌سازد کجا بگذارم؟

ما آن را در پوشه wp-content/plugins/sms-bridge گذاشتیم و فعال کردیم؛ ارقام فارسی و شماره ناقص را در functions.php قالب فرزند هم آزمودیم و نتیجه یکی بود.

وب‌هوک المنتور چه می‌فرستد و می‌شود هدر یا JSON فرستاد؟

در ویجت Form برچسب فیلدها نام پارامتر می‌شود، به‌اضافه form_id و form_name (و با اکشن Email شش پارامتر دیگر). تنظیم‌های اکشن جایی برای هدر یا JSON ندارد؛ با فیلتر request_args هدر و بدنه JSON را عوض کردیم.

تصویر سمانه جعفری
سمانه جعفری
پیشنهاد میکنیم این مقالات را هم بخوانید

دیدگاه یا پرسش خود را بنویسید