آموزش پرداخت درون برنامه ای کانستراکت و جلوگیری از هک آن
#1
به نام حق
با سلام و احترام خدمت دوستان عزیز

الوعده وفا!
با توجه به اینکه چند ساعت پیش بازی مدافعان حرم رو در کافه بازار ، منتشر کردم، و تا بیام یه چند ساعتی، اونم بعد از 4 ماه روزی 17-18 ساعت کار، استراحت کنم، VNG عزیز، یادم انداخت که یه قولی دادم! 17 

برای تهیه این آموزش شاید زمان کمی گذاشته باشم، اما برای تجربه کسب کردن برای پیاده سازی روشی که اصلا هیچ مستند و مطلبی براش نیست(تقریبا) حدود 10-12 روز وقت گذاشتم، پس خواهش میکنم خواهش میکنم و خواهش میکنم، قبل از هر سوال و جوابی و ...، حتما متن آموزش رو به طور کامل، از اول به آخر بخونین و اگرم مشکلی دارین، به متن آموزش مراجعه کنین و اگه مشکل رفع نشد، بعد سوال بپرسین، اینو از این بابت میگم که من خودم گاها، قبل از اینکه کامل متن آموزشی رو بخونم، در موردش سوال میاد تو ذهنم، غافل از اینکه، جواب توی خود آموزش بوده. ( فکر میکنم نصفتون این 5 خط رو نخوندین ها! )


توجه داشته باشید، برای استفاده از این روش، شما به یک هاست رایگان( بهتره پولی باشه) یا یک سرور مجازی مناسب نیاز دارید.
داشتن پیش زمینه ای در php توصیه میشه که اگه ندارین، اصلا غصه نخورین، کد ها رو کامل براتون میذارم.


القصه و الغصه!

اول اینکه چرا الغصعه! ؟؟؟

با توجه به اینکه پرداخت درون برنامه ای ، اولین بار توسط Adply برای کانستراکت و به همت مهدی ابراهیمی عزیز، تهیه شد، اما این پلاگین، همواره مشکلاتی رو داشته که نمیشه ازش گذشت، اما برای شروع پلاگین واقعا عالی بود و شخضا به من امیدی تازه برای برگشت به سوی کانستراکت داد.
برخی از مشکلات این پلاگین عبارت است از: مشکلات مربوط به عدم اجرای دقیق روی همه ی گوشی ها و عدم ارائه ی توکن خرید و مواردی دیگر.

نوبت پلاگین های آقا میلاد رسید! 17 
این پلاگین ها که برای مارکت های بازار، مایکت، ایران پس و .. تهیه شده، به خوبی کار میکنن و مشکلات ادپلی رو در زمینه ی اجرا روی گوشی های مختلف ندارن(بر حسب تست من البته) اما باز هم تون خرید رو بر نمیگردونن!

اینجاست که پلاگین دیگری رو معرفی میکنیم که همه ی شما عزیزان، قبلا اون رو دیدین، اما قبل از معرفی باید بگم که، این پلاگین و مستندات git اون هم یه سری مشکلات داره، ولی شما رو از دست برنامه هایی نظیر لاکی پچر و یا هک شدن با نرم افزارهای دیگه، راحت میکنه.
( اینجا جا داره از آقا مهدی حیدرزاده بابت راهنمای ها و البته تغییر مستندات گیت هاب )

معایب این روش جدید:
تقریبا تنها ترین عیب و البته اصلی ترین اون اینه که در صورتی که در خرید، مشکلی بوجود بیاد، باید کاربر از حساب کاربری خودش در بازار، خارج و دوباره وارد حساب کاربریش بشه. که اینم برمیگرده به خود کافه بازار ، و روی مایکت و ... مشکلی نیست.

دوستان، اصلی ترین مسئله در مورد پرداخت درون برنامه ای بازار، اینه که این کدهای بازار، دقیقا همون کدهای گوگل پلی هستند و هر مشکلی که گوگل پلی داره رو بازار هم داره البته بیشتر!


خب برای شروع باید بگم که حتما حتما حتما! این مستندات بازار رو بخونین!
302 Found

و مهمترین قسمتش که:
302 Found

هست رو کامل و به نظرم دو سه مرتبه بخونین، حتی اگه کمترین مقداری ازش متوجه بشین.(واقعا لازمه)


پس از مطالعه کامل لینک های بالا،وارد حساب توسعه دهندگان شوید!
همونطور که خودبازار، گفته به لینک قسمتی که گفته برین برای ایجاد Client ، ام ظاهرا لینک مشکل داره، پس به این لینک برین.

302 Found

و روی دکمه ی سبز رنگ:   Client جدید کلیک کنین.

در کادر باز شده، از شما یک آدرس میخواد که نوشته:   Redirect URI

فعلا دست نگه دارین!

شما باید یک فایل( در این آموزش php ) درست کنین و در سرور ( هاست ) قرار بدین، برای قسمت Redirect URI

ذر واقع، اینطوری بازار میفهمه شما یک هاستی دارین که میخواین باهاش از API درون پرداخت استفاده کنین.

خب برای محتویات فایل میتونین از کدهای زیر کپی بگیرین و بریزین توی یک فایل php با نام مثلا : uri.php ذخیره کنین و بریزین توی هاست.

کد:
<?php

?>
خب مثلا من میریزم توی هاست roozeno.ir که میشه :

302 Found

و بعد این آدرس رو در اون کادری که بازار در قیمت Client جدید ، میخواست وارد میکنین.

بازار به شما دو تا رشته کد میده که اولی:CLIENT ID و دومی : CLIENT SECRET و سومی که همون آدرسی هست که در بالا دادین.

امکان حذف این رشته ها هم با استفاده از دکمه ی حذف وجود دارد که البته، اگه برای برنامه تون درست کردین، دیگه نباید حذف کنین یا لااقل باید مقادیر رو در فایل های بعدی که میگم، تغییر بدین.

[تصویر:  3rnc_01.png]

اگه مستندات بازار رو بخونین به شما گفته که این ها باید محرمانه بمونن!

خب ، شما الان کلایت Id و سکرت Id رو دارین،

طبق گفته بازار، شما باید Authorization Code  رو هم داشته باشین، پس مقادیر UIR و CLIENT_ID رو در آدرس زیر جایگذاری کنین و در مرورگر درخواست بدین.
کد:
[url=https://pardakht.cafebazaar.ir/devapi/v2/auth/authorize/?response_type=code&access_type=offline&redirect_uri=]پرداخت[/url]<REDIRECT_URI>&client_id=<CLIENT_ID>



که مثلا باید بشه:


کد:
https://pardakht.cafebazaar.ir/devapi/v2/auth/authorize/?response_type=code&access_type=offline&redirect_uri=http://roozeno.ir/uri.php&client_id=t2GrOIo9TbhJ

که در آدرس بالا، من CLIENT_ID خودم رو کامل نذاشتم، ولی شما باید بذارین و در مرورگر اجرا کنین آدرس رو.

اگه مشکلی در آدرس نباشه، یه کادر شبیه عکس زیر در سایت بازار براتون باز میشه:

[تصویر:  wnaz_2.jpg]روی تائید کلیک کنید.

بعد از کلیک کردن روی تائید، همون آدرس uri.php شما براتون میاد که یه کد جلوش نوشته شده اون رو کپی کنین جایی که لازمه.

مثلا:

[تصویر:  r2hs_3.jpg]

تا اینجای کار شما رو انجام بدید تا بقیه آموزش رو قرار بدم.
سوالات رو فقط در موضوع زیر بپرسین، لطفا.

پرسش و پاسخ پرداخت درون برنامه ای و جلوگیری از هک




#2
قسمت دوم:

به نام حق
سلام مجدد

دوستان عزیز، در ادامه آموزش شما باید با پلاگین های مخصوص پرداخت آشنا بشین که تقریبا خیلی از ما، این پلاگین ها رو از قبل داریم، اما بازم لینکشو میذارم.

CanvasPlus_IAP

یا مجموعه ی کامل رو از

CanvasPlus_IAP

دریافت کنین، مثال های خرید هم توش هست.( البته حتما ادامه آموزش رو ببینین، قبل از هر تست کردنی)

این فایل فشرده بالا، دو تا پوشه توش هست که یکی

cocoon_canvasplus
و یکی

cocoon-inapps


حتما همین دو تا پوشه رو بریزین داخل پوشه ی پلاگین های کانستراکت و نرم افزار رو یک مرتبه ببندین و باز کنین.

خب، تا اینجای کار شما فایل uri.php رو دارین، کلاینت id و سکرت id و Authorization Code و پلاگین ها رو.


دقت دقت دقت:

روش کار به این صورته که :

اول : با استفاده از پلاگین کوکون، خرید رو انجام میدیم.
دوم: توکن خرید رو بعداز خرید موفقیت آمیز، میگیرم از اکسپرشن و بعد اونو توسط ایجکس به سرور میفرستیم.
سوم: از طریق سرور وصل میشیم به بازار و چک میکنیم که اون توکن خرید، واقعا وجود داره یا نه؟
چهارم: اگه همه چیز اوکی بود، یه پیام برگشت به بازی میفرستیم که یعنی درست بوده.
پنجم: بعد از تائید ، اون موردی که خرید شده رو، روی بازی افزایش میدیم یا هر چی.
ششم: همچنین اول تمام این کارهارو انجام بده بعد کالا رو مصرف کنه تا وقتی هنوز اضافه نشده کالا مصرف نشه.


6 مرحله ی بالا، کاملا قضیه رو مشخص میکنه، اگه با پلاگین cocoon-inapps کمی کار کنین، میبینین که به شما در اکسپرشن هاش، یه سری دسترسی ها میده! و یکی از اونا توکن خرید هست. یعنی اکسپرشن :  PurchaseTransactionId

مجددا ! دقت دقت دقت===> در این پلاگین ، شما نیازی نیست کد RSK که بازار بهتون میده رو ، جایی از پلاگین وارد کنین و همین که برنامه رو به بازار بفرستین، کافیه! ( یعنی شناسوندن RSK به پلاگین، نیازی نیست، البته کلا نمیشه جایی واردش کرد توی این پلاگین)


روش کار به صورت کلی، در مثال هایی که شما در فایل فشرده ی بالا، قرار دادم، میتونین ببینین، اما این سورس های موجود در فایل فشرده، فقط برای خرید هستند و نه برای چک کردن!

برای چک کردن باید کار دیگه ای بکنین.

همونطور که در مرحله ی 2 عرض شد، شما باید توکن خرید محصول مدنظرتون  که میخواین رو توسط Ajax به سرورتون بفرستین که سرورتون باید بعدش وصل بشه به بازار و چک کنه آیا خرید شده یا نه؟ و یه خروجی JSON میده که شما میتونین اونو بررسی کنین.

مراحل کار به اینصورته که شما هم میتونین برای هر محصول، فایل به خصوصی رو ( فایل php در اینجا ) ایجاد کنین و با ایجکس بهش وصل بشین، و هم میتونین یه تابع داشته باشین ( Function در php ) که به اون پارامترهای خودتون رو ارسال میکنین و تابع رو طوری تنظیم میکنین که براتون نام محصول و توکن خرید رو جایگزین کنه.
نگران نباشین، کدهای مخصوص php رو براتون قرار میدم.

ابتدا برای تست، یک فایل html که در واقع فرم تست خرید هست رو ایجاد کنین با کدهای زیر و اونو با نام form.html ذخیره کنین و بریزین توی هاست:

کد:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>فرم تست خرید</title>
</head>

<body>

<form action="check.php" method="post" >

<input type="text" name="product" id="product" />

<input type="text" name="tokenid" id="tokenid" />

<input type="submit"/>


</form>

</body>
</html>

یه توضیح کوچیک در مورد کد بالا:
شما فرمی با دو تا text field ایجاد کردین که اولی برای id محصول در بازار و دومی برای توکن خرید هست. این فرم به فایلی به نام check.php متصل میشه که این فایل حاوی کدهایی هست که در زیر میاد. ( یعنی همون فایل چک کردن خرید که توش تابع و ... داره)


خب، شما یه فایل دیگه برای چک کردن لازم دارین که محتویاتش ، در صورت اینکه، خودتون بلد نیستین یا حال تعویض یا نوشتن کد رو ندارین، باید کدهای زیر باشه:


دقا کنین، نیازی به تغییر فیلدها و خیلی چیزهای دیگه نیست، چون مطمئن هستم کسانی که php بلد نیستن، یه جایی رو جا میندازن و کلی مشکل براشون درست میشه، پس لطفا الکی دستکاری نکنین. ( فقط کسانی که بلد هستند که بازم میگم نیازی نیست )

البته یه سری جاها رو باید جایگزین کنین که من خودم میگم کجا!

کد رو تکه تکه میذارم و توضیح میدم، بعدش به صورت کامل:

کد:
header('Access-Control-Allow-Origin: *');

این خط برای چاپ کردن هدر هست.

کد:
if(!empty($_REQUEST['product']) || !empty($_REQUEST['tokenid']))

اینجا با دستور if چک میکنیم که ایا فرم ارسالی ( یا محتویات ارسالی از برنامه یا بازی ) ارسال شده یا نه؟
در صورت تغییر در id های فرم یا برنامه یا بازی، باید product و tokenid رو عوض کنین. ( آقا اصلا دستکاری نکنین 4  )

کد:
$tokenidsent = $_REQUEST['product'];
$productnamesent = $_REQUEST['tokenid'];

اینجا ، اون تا فیلد رو میریزیم توی دو تا متغیر!

کد:
function bazaar($product_id,$purchase_token){
..........................
}

یک تایع درست میکنیم که اینجا اسمش bazaar هست و دو پارامتر هم باید برای چک کردن بهش ارسال کنیم. یعنی
کد:
$product_id,$purchase_token

این دو تا رو!

کد:
$package_name ='';

یک متغیر با مقدار رشته ای برای نام پکیج لازم دارین، پس package name برنامه یا بازی رو باید بذارین وسط دو تا '' !

کد:
$refcode = '';

یک متغیر رشته ای که برای قراردادن اون کدی هست که در قسمت اول گرفتین رو بذارین بین '' .

کد:
$url = 'https://pardakht.cafebazaar.ir/devapi/v2/auth/token/';

اینو عوض نکنین!

کد:
$data = array('grant_type' => 'refresh_token', 'client_id' => '', 'client_secret' => '', 'refresh_token' =>  $refcode);

بین دو تا '' در مقابل
کد:
'client_id' =>

مقدار کلاینت id و برای '' در مقابل
کد:
'client_secret' =>

هم مقدار کلاینت سکرت رو بذارین.

یه سری کدهای دیگه هم هست که در زیر میبنین که مربوط میشه به ساخت کوئری توسط http و درخواست از آدرس مخصوصی که برای API درون پرداخت هست که توضیح نمیدم، گیج کننده اس.
و در آخر کار هم باید تابع رو echo یا همون چاپ کنین.

کد:
echo bazaar($tokenidsent,$productnamesent);

اگر هم شرط اولی که برای مقادیر فرم گذاشتیم درست نبود، میتونیم تهش یه else بذاریم و یه ارور رو چاپ کنیم.


کد کامل زیر رو پس از تغییر مقادیری که در بالا گفتم، بریزین توی فایل check.php و بریم برای قدم بعدی:

کد:
<?php
header('Access-Control-Allow-Origin: *');
if(!empty($_REQUEST['product']) || !empty($_REQUEST['tokenid'])){


$tokenidsent = $_REQUEST['product'];
$productnamesent = $_REQUEST['tokenid'];


function bazaar($product_id,$purchase_token)

   {

       $package_name ='';

       $refcode = 'XyR5wNLEfOlxKYbhrdr5brdb6XhMg5';

       $url = 'https://pardakht.cafebazaar.ir/devapi/v2/auth/token/';

       $data = array('grant_type' => 'refresh_token', 'client_id' => '', 'client_secret' => '', 'refresh_token' =>  $refcode);

       

       $postString = http_build_query($data, '', '&');


       $opts = array('http' => array(

           'method'  => 'POST',

           'header'  => 'Content-type: application/x-www-form-urlencoded',

           'content' => $postString

       ));

       $context  = stream_context_create($opts);

       $result = file_get_contents($url, false, $context);

       $jsonResponse = json_decode($result, true);

       $access_token = $jsonResponse['access_token'];

       $res = file_get_contents("https://pardakht.cafebazaar.ir/devapi/v2/api/validate/$package_name/inapp/$product_id/purchases/$purchase_token/?access_token=$access_token");

       $jsres = json_decode($res, true);

       return $jsres['purchaseTime'];


$timepurCount= strlen(utf8_decode($jsres['purchaseTime']));
        
        return $timepurCount+17;



   }
    
echo bazaar($tokenidsent,$productnamesent);
    

}else{

echo "error";

}

    
?>

البته کد رو میشه خلاصه تر هم کرد، ولی اصلا نیازی نیست!

خب شما میتونین برای تست، اگه تا الان توی برنامه هایی که داشتین، خرید درون برنامه ای ، داخل بازار ثبت شده، id محصول , توکن خرید رو در فرم html وارد کنین تا نتیجه رو ببینین.

ادامه آموزش، بزودی....



#3
سلام مجدد
در ابتدا عذرخواهی صمیمانه من رو بپذیرین دوستان.
گرفتاری های شخصی ول کن نبودن و نیستن!

آموزش رو ادامه میدم با نگاه کلی به قضیه و سورس مربوط به پرداخت.

شما تا اینجای کار، زمانی که یک خرید رو تست میکنین، یه عدد 13 رقمی بهتون داده میشه که در واقع چاپ شده مقدار زمان برحسب میلی ثانیه از نبدا 01/01/1970 میلادی است.
البته اگه کد رو بررسی کنین، میبینین که چند تا چیز دیگه رو هم برای شما برگردون میکنه به صورت JSON که شما میتونین اونا رو هم داشته باشین.
توضیحات اضافه رو در :
302 Found

consumptionState
وضعیت مصرف محصول. در صورتی که محصول مصرف شده باشد، مقدار آن برابر با ۰ و در غیر این‌صورت برابر ۱ خواهد بود.
purchaseState
وضعیت خرید محصول. در حالت عادی مقدار آن برابر ۰ است، در صورت بازگشت خرید (Refund) مقدار آن ۱ خواهد بود.
kind
نوع منبع مورد دسترسی. مقدار آن در این متد همیشه برابر androidpublisher#inappPurchase است.
developerPayload
payload ارسال شده توسط برنامه فروشنده در هنگام خرید.
purchaseTime
زمان خرید بر حسب میلی‌ثانیه از مبدا ۱۹۷۰/۱/۱ میلادی.



که البته برای چک کردن بهتره از همین زمان استفاده کنین در حالات مختلف: مثلا تعداد کاراکتر رو برگردون کنین، یا تعدادش رو جمع بزنین با یه عدد دلخواه و بعد برگردون کنین و هر چیز دیگه ای.


خب ، اینجا کاملا مشخصه که شما با استفاده از دستورات پلاگین Ajax باید درخواستی به همین فایل check.php بفرستین. دقیقا همون کاری که توسط form.html میکردین.

چطوری؟

در واقع شما میتونین با روش های REQUEST و GET و POST اطلاعات رو بفرستین.
من در فایل form.html به صورت REQUEST این کار رو کردم.

**دوستانی که آشنایی ندارن با این موارد، بی خیال شن یا برن یاد بگیرن ( HTML )

خب، شما دقیقا میتونین به جای همون کلمه REQUEST از دوتای دیگه استفاده کنین و تست کنین. میبینین که کار میکنه. با این تفاوت که در حالت GET ، رشته ای به ادامه ی آدرس فایل form.html اضافه میشه!

این به چه درد میخوره؟ خوبی این روش اینه که شما برای ارسال Ajax باید از همین روش GEt استفاده کنین و رشته ای رو به فایل check.php بفرستین.
یک نمونه از رشته ای که باید بفرستین رو من در زیر آوردم:

کد:
http://www.site.ir/check.php?product=productID&tokenid=tokenID


توجه کنین که عبارت site.ir باید به آدرس سایت شما عوض شود.
عبارت check.php رو اگه اسم فایل رو عوض کردین، باید عوض کنین.
عبارت productID همون ID مربوط به محصولی هست که در مارکت ایجاد کردین.
عبارت tokenID همون توکنی هست که شما توسط پلاگین خرید، دریافت میکنین یا در اینجا برای تست، همون توکنی که از قبل دارین رو وارد کنین.

من یه سورس ساده از همین موارد رو در زیر قرار دادم:

checkphptoken

یا

http://roozeno.ir/c2/sample/checkphptoken.capx


**جهت سهولت در کار، شما میتونین مقادیر متغیرهای ProductID و tikenID و siteURL رو در سورس مقدار دهی کنین و تست بگیرین.



هر مشکلی تا اینجا هست بپرسین.
سوالات فقط در :
پرسش و پاسخ آموزش پرداخت درون برنامه و جلوگیری از هک

ادامه رو فردا میذارم ان شاء الله.


#4
سلام

ادامه ی آموزش رو به صورت یه سورس کامل و توضیحاتی در این رابطه خدمت دوستان عزیز، تقدیم میکنم.

این قسمت کد به پست دوم اضافه شده است. یعنی شما باید فایل check.php رو ویرایش کنین.
این قسمت از کد php به این صورت عمل میکنه که تعداد کاراکتر رشته  ی گرفته شده رو میشماره و برای امنیت بیشتر با یه عددی جمع میزنه و چاپ میکنه.
شما مقدار 17 رو میتونین عوض کنین.
البته در سورسی که میدم هم باید تغییری بدید که اونو عرض میکنم.


کد:
$timepurCount= strlen(utf8_decode($jsres['purchaseTime']));
        
        return $timepurCount+17;



#5
خب آخرین قسمت از آموزش که شامل سورس کامل پرداخت درون برنامه ای و جلوگیری از هک و همچنین آموزش ویدئویی همه ی قسمت ها رو قرار دادم.

آموزش ویدئویی:

http://roozeno.ir/c2/video/IAP_And_Anti_Hack.mp4

توضیح بدم که اگه آموزش همراه با تپق و مشکلاتی همراه بود و کیفیت کم است، قبلا عذرخواهی میکنم.


سورس :

http://roozeno.ir/c2/sample/checkphptoken_Complete.capx




برای خروجی هم باید آدرس گیت هاب زیر رو وارد کنین.
البته این از گیت اقای حیدرزاده ، فورک شده. که نهایت سپاسگذاری رو از ایشون دارم.

https://github.com/mostafanastary/iap-ba...googleplay




موضوع‌های مشابه…
موضوع نویسنده پاسخ بازدید آخرین ارسال
Star مهم آموزش خروجی اندروید روی سیستم شخصی rezamms 127 82,184 1402/8/24، 09:00 عصر
آخرین ارسال: mehdiosw
  مهم آموزش تصویری خروجی مستقیم - یکبار برای همیشه! rezamms 33 19,757 1401/2/13، 09:39 عصر
آخرین ارسال: kamran_cn
  خروجی اندرید davinmstr1 2 2,423 1400/8/4، 10:23 عصر
آخرین ارسال: ᔕinaᗪehghani
  AAB (بسته برنامه اندروید) چيست؟ + نحوه خروجي گرفتن در كرودوا ᔕinaᗪehghani 15 7,868 1400/6/21، 01:55 صبح
آخرین ارسال: mehdi1100
  رفع مشکل خروجی فونگپ (: M.gh 11 7,955 1400/4/10، 02:17 صبح
آخرین ارسال: oak

پرش به انجمن: