סליקת אשראי באמצעות PHP

מהן עקרונות סליקת כרטיס האשראי? מהו ההבדל בין אימות לאילוץ וכיצד ניתן ליישם זאת באמצעות PHP?

צילום: flickr, cc-by, Images_of_Money

סליקה בכרטיס אשראי היא דבר שמשום מה די מפחיד מתכנתים והאמת היא שאני לא יודע למה. במאמר הזה אני אסביר מעט על העקרונות של הסליקה ואדגים סליקה של טרנזילה. כמובן שאפשר להשתמש בהדגמות על מנת להשתמש בשירותי הסליקה של כל חברה אחרת (ויש המון).

ראשית, מהי סליקה? סליקה היא שם כולל לאימות ואילוץ עסקאות של כרטיסי אשראי ברשת האינטרנט. או הפעולות שמתרחשות מאחורי הקלעים בין השלב שבו הלקוח מכניס את פרטי כרטיס האשראי ועד לשלב שבו אתה מקבל את הכסף. על מנת לקחת מספר כרטיס אשראי של לקוח ולעשות איתו משהו אנחנו חייבים חשבון בחברת סליקה. יש לא מעט חברות סליקה בשוק וכל עוסק מורשה יכול ליצור איתן קשר ולאחר בדיקה והסברים ליצור שם חשבון. עם יצירת החשבון אתם מקבלים שם משתמש שמזהה אתכם במערכת וסיסמה.

אימות מול אילוץ

אימות כרטיס אשראי הוא בעצם בדיקת כרטיס האשראי על מנת לבדוק שהוא תקין ושהפרטים הקשורים אליו כמו שם בעל הכרטיס, מספר ה-CCV (מספר הבטחון מאחורי הכרטיס) ומספר תעודת הזהות של בעל הכרטיס נכונים. וכמובן בדיקה שהכרטיס תקין ובתוקף. אימות לא גובה מהלקוח כסף ולא גורם לו להיות מחויב.

אילוץ הוא הפעולה שמעבירה כסף מבעל כרטיס האשראי אל הכיס שלנו. ניתן לבצע אילוץ ללא אימות וניתן לבצע אילוץ לאחר אימות.

הדרך המקובלת באתרים קטנים היא לבצע אימות באמצעות סליקה ולאחר משלוח המוצר, לבצע אילוץ ידני באמצעות המערכת.

ביצוע אימות

על מנת לבצע אימות, כל מה שעלינו לעשות זה לשלוח את פרטי כרטיס האשראי ופרטים נוספים אל שרת הסליקה. שרת הסליקה מחזיר אישור (או במידה ויש בעיה כלשהי, מחזיר את סיבת הבעיה). האישורים ושמות הפרמטרים תלויים בשירות הסליקה.

אני אדגים באמצעות טרנזילה. טרנזילה מבקשת לתהליך האימות את הפרמטרים הבאים:

supplier
sum
price
cname
amount
address
city
zipCode
email
cardNum
eYear
eMonth
cvv2
myid

כאשר כל פרמטר צריך שיכיל את המידע הרלוונטי. cvv2 צריך להכיל את ה-CVV של הכרטיס, myid צריך להכיל את מספר תעודת הזהות של בעל הכרטיס וכך הלאה – לפי מה שמערכת הסליקה רוצה.

במקרה של טרנזילה יש בקשה לעוד שני פרמטרים עם הערכים הבאים:
task=Doverify
tranmode=V

על מנת לשלוח את הפרמטרים באמצעות Curl, אנו צריכים להכין מחרוזת טקסט ארוכה שלהם – בדיוק כמו בטופס. משהו כמו:

supplier=SUPPNUMBER&sum=10.00&price=5.00&cname=מוצרכלשהו&amount=1&address=רחוב שקר כלשהו 100&city=פתח תקוה&zipCode=332311&email=example@example.com&cardNum=XXXXXXXXXXX&eYear=2015&eMonth=12&first_name=רן&last_name=בר-זיק&cvv2=732&myid=33444447&task=Doverify&tranmode=V

את הפרמטרים האלו אנו יכולים לשלוח אל טרנזילה באמצעות Curl. אני הסברתי איך להשתמש ב-CURL וב-PHP באופן מאד מפורט במאמר על CURL וב-PHP. כך יראה הקוד למשל:

$host = 'https://secure5.tranzilla.com/31.cgi'

$params = 'supplier=SUPPNUMBER&sum=10.00&price=5.00&cname=מוצרכלשהו&amount=1&address=רחוב שקר כלשהו 100&city=פתח תקוה&zipCode=332311&email=example@example.com&cardNum=XXXXXXXXXXX&eYear=2015&eMonth=12&first_name=רן&last_name=בר-זיק&cvv2=732&myid=33444447&task=Doverify&tranmode=V';

$curl_connection = curl_init();
curl_setopt($curl_connection, CURLOPT_URL, $host);
curl_setopt($curl_connection, CURLOPT_POST, 1);
curl_setopt($curl_connection, CURLOPT_FAILONERROR, true);
curl_setopt($curl_connection, CURLOPT_POSTFIELDS, $params);
curl_setopt($curl_connection, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curl_connection, CURLOPT_SSL_VERIFYPEER, 0);

// actual curl execution perfom
$result = curl_exec($curl_connection);

 

 

 

// on error - exit with error message
$error = curl_error($curl_connection);
if(!empty($error)) {
die($error);
}
curl_close($curl_connection);

במידה והכנסנו את כל הפרמטרים באופן תקין, אנו נקבל תשובה. התשובה שאנו מקבלים מטרנזילה היא קוד מסוים כאשר '000' נחשב לקוד תקין ושאר הקודים הם קודים של שגיאות. כאשר טרנזילה מפרטת את הקודים של השגיאות. ניתן לבנות מערכת קטנה של switch-case כדי שתציג בפני הלקוח באופן מובן את השגיאה. במידה והתשובה '000' אנחנו נדפיס אישור ונוכל לראות את האימות במערכת. לאחר אספקת המוצר ללקוח אנו נוכל ללחוץ על אילוץ ולסיים עם העסקה כשכולם מאושרים.

באופן עקרוני ההדגמה כאן נעשתה על פי טרנזילה, אבל עם קצת שינויים ניתן להתאים אותה לכל שירות סליקה אחר כגון 'paypal' ואחרים.

הפוסט פורסם לראשונה ב"אינטרנט ישראל"

רן בר-זיק

מתכנת PHP מנוסה. בנוסף להיותי מתכנת, יש לי נסיון ככלכלן וכמנהל פרויקטים. כיום אני עובד כמתכנת בחברת HP ובעל האתר אינטרנט ישראל המוקדש לפיתוח. אני נשוי ליעל ואב לארבעה ילדים – עומרי, כפיר, דניאל ומיכל.

תגיות לכתבה:

להגיב

13 תגובות

  1. מאת רם פרס:

    שלום,
    תרשה לי להגיב מכיוון אחר טיפה:
    ברגע שאתר כלשהו מקבל כרטיס אשראי הוא מחוייב לעמוד בתקן PCI DSS.
    תקן זה הוא תקן אבטחת מידע אשר נועד למנוע גניבת נתונים אשראי מבתי עסק.
    למען הסר ספק: התקן חל על בית העסק גם אם הוא לא שומר את פרטי כרטיס האשראי ומעביר אותם ישירות לחברת האשראי (הגיוני, אם האתר יפרץ יוכל הפורץ להתקין סוס טרויאני אשר יגנוב את הנתונים בעת המעבר)
    יישום התקן הוא לעיתים מסובך וגם יקר.
    לשמחתנו, ניתן לעמוד בתקן באופן פשוט יחסית על ידי שימוש בדף תשלום אשר מתארח אצל ספק שרותי התשלום.
    רוב ספקי השירותים (כמו גם טרנזילה שהבאת בדוגמה) מאפשרים לארח את דף התשלום אצלם: בעת ביצוע תשלום הלקוח מועבר (redirect) לדף שמאוחסן פיזית אצלם.
    בכך נחסך מבית העסק רוב כאב הראש וההוצאות הכרוכות ביישום תקן PCI DSS.

  2. מאת ניצן:

    הסיבה שהטמעה של סליקה "מפחידה מתכנתים" היא לא בגלל הקושי או הסיבוכיות. בין אם אתה משתמש ב curl או ב soap בסופו של דבר מדובר בהטמעה של פרוטוקול, קבלה של נתונים והעברה שלהם הלאה.

    אז איפה הבעיה, או למה אני נמנע מלפתח ממשקי סליקה – בעיקר כי זה אומר שאני מתעסק פה עם כסף של מישהו. אם אתה לקוח גדול שמשלם טוב על הזמן שלי, אני אעשה את כל הבדיקות הנדרשות והכל יהיה טוב ויפה, אבל בישראל, רוצים אתמול, בפחות ויותר טוב – וזה שילוש אחד שאי אפשר לעמוד בו. אז זה לא שאני מפחד לממש סליקה, זה שאני משתדל להימנע מזה עבור לקוחות קטנים. זהו בעיקר.

  3. מאת רונפל:

    ההערה של רם אכן במקום וחשוב להתייחס גם להגבלות או לפחות להכיר אותן כדי להימנע מכאבי ראש בשלבים מאוחרים יותר (לדוגמא האיסור לשמור CVV / CVC וכו')

  4. יפה לכם שהתחלתם לעבוד עם רן בן זיק בשיתוף פעולה!
    גם ניוזגיק וגם אינטרנט ישראל פשוט אתרים מעולים, ביחד זה שילוב בלתי מנוצח.

  5. מאת סנונית קטנה:

    אם אתה מתכנת PHP מנוסה למה אתה מלמד כמו חובבן ועושה טעויות בסיסיות. ככה עושים את זה נכון וברור. http://pastebin.com/qSt7YiXY חשוב להבין ש-CURL יכול להכשל *גם* ברמת ה-PHP ולא בגלל שגיאה פנימית, ובגלל ש-curl_exec מגיע לפני בדיקת השגיאה הוא יכול להכשל לפני, ולא להגיע בכלל לשגיאה. ובסליקה של אשראי חייבים להתמודד עם המצב הזה כראוי בעזרת Exception מתאים, אחרת לא תדעו מה בדיוק קרה שם כי הסקריפט יפסיק לפעול.

    • שלום סנונית, אני מודה לך על הסגנון והנוסח.

      בדוגמאות שלי אני משתמש בדוגמאות הפשוטות ביותר. try-catch לא קשורות לנושא וכל מתכנת אמור להשתמש בהן, במידת הצורך. המאמר הזה לא אמור ללמד try-catch.

      בנוגע לדוגמה שהבאת, לא תמיד אנו רוצים שהבעיה תודפס קבל עם ועדה – לעתים כדאי לרשום את זה ב-error-log של PHP או כל לוג אחר, וכמובן לבצע fallback אחר. אני לעולם לא משתמש ב-try-catch שמדפיס טעויות באתרי production.

      אפשר לבוא ולהצביע על טעויות או להציע הצעות לשיפור, אבל הסגנון הדוחה הזה הוא ממש לא לעניין.

  6. מאת סנונית קטנה:

    השימוש ב-die היא רק כדי לשמור על עקביות עם הדוגמא שאתה הראתה זה אינו נכון להשתמש ב-die באף מקרה חוץ מ-debug. מפריע לך הסגנון סליחה, הדוגמא שלך ממש לא ברורה, מה זאת הצורה הזאתי להראות משתנים שאתה שולח ל-POST כמחרוזת עם תווים בעברית ואנגלית למה מישהו שרוצה ללמוד צריך לפענח את זה? אם זה עניין של יעילות (ואני לא בטוח שקיים) למה להראות את זה בצורה כזאת שאתה רוצה ללמד מישהו אחר? לא יכולתי שלא להבחין בתאור שלך ב-"מתכנת PHP מנוסה" – וזה הפריע לי, לא הייתה כוונה לפגוע בך, אבל ככה השגתי את התשומת לב שלך. אולי בדוגמא הבאה שלך תשקיע קצת יותר. ובקשר לבעיה עצמה, זה פשוט, כעובדה curl_exec יכול להכשל בשגיאה מסוג FATAL, בין היתר כאשר קרה וחסר זיכרון מסיבה כלשהי ובמקרים אחרים, במקרה כזה הסקריפט יעצר ולא ימשיך כדי לכתוב LOG וכדומה… מה יקרה אז לסליקת האשראי שלך? איך תדע מה בדיוק קרה שם? בכל מקרה אחר, אולי זה לא היה משנה, אבל שאתה סולק כרטיס אשראי, כדאי שיהיה try ו-catch, אחרת זה פשוט לא יהיה נכון, מתכנת PHP (אולי לא כל כך מנוסה) שירצה להשתמש בדוגמא שלך כדי לסלוק אשראי, יעשה טעות קריטית.

    • אפשר להשיג את תשומת הלב שלי, גם אם כותבים באופן ענייני ולא מתלהם.

      כמובן שלא יצאתי נגד השימוש ב-try & catch, רק נגד הדוגמה שלך שהשתמשה ב-die שעדיף לא להשתמש בו בשרתי production – בטח שלא עם כתיבת הודעה. כיוון שאתה הצגת את הקוד הזה כמשהו שאתה משתמש בו באופן יום יומי.

      אני בוודאי שלא חושב שצריך לעשות copy&paste לקוד שפרסמתי. בגלל זה מוסבר שמדובר בהדגמה – לא בסניפט או משהו שאפשר להעתיק אותו (אחרת בחיים לא הייתי משתמש ב-die). ההסבר הוא על חלק נקודתי בממשק – ולא היה טעם להביא את כל הקוד הסובב אותו – היכן לעצור? ב-try-catch? בסוגיות אבטחה? בעניין ה-SSL? אין סוף לזה. תחמתי גבול והסברתי עד הגבול הזה.

      בנוגע לשאר דבריך. מה לעשות שאני מתכנת PHP מנוסה ואני אמשיך להיות מנוסה גם אם אתה חושב שאני לא יודע מה זה try-catch ומתי להשתמש במבנה הזה וגם אם אתה חושב שאולי מוטב היה להשתמש בהן בדוגמה הזו. אני לא השתמשתי ב-try & catch בדוגמה הזו והסברתי גם למה בתגובה הקודמת. אם יש לך משהו להוסיף מעבר לכך, אני אשמח לשמוע ואשמח עוד יותר אם תשתמש בשם האמיתי שלך או בכינוי האמיתי שלך ואם אתה לא רוצה לעשות את זה כאן, המייל שלי תמיד פתוח – בנושא הזה ובנושאים אחרים.

      על אף שחילוקי דעות – במיוחד בנוגע ללימוד, הסברים ודוגמאות קיימים תמיד, יש דרך ללבן חילוקי דעות באופן מכובד ובלשון הולמת תוך כדי מתן כבוד הדדי, אני אשמח אם תכבד אותי כמו שאני מכבד אותך – אפילו בלי להכיר אותך.

  7. מאת סנונית קטנה:

    אני לא מתכוון שאתה לא מנוסה, אני בטוח שכן, ולכן ציפיתי לדוגמא יותר מושקעת, לא היה לי טענות אם לא הייתה כזה. שליש מהפוסט מכיל את רשימת הפרמטרים שאתה שולח, בעוד שבקוד, איפה שזה באמת צריך להופיע – יש מחרוזת ארוכה, אני עוסק ועסקתי בהדרכה, ולכן הפרזנטציה של הדוגמא שלך מפריע לי כל כך. בקשר לשימוש של try and catch – אולי האפשרות CURLOPT_FAILONERROR מכסה על curl_exec מבחינת השגיאות, אבל כאשר יוצרים תקשורת מהסוג הזה לשרת *לדעתי* צריך להתייחס לכל התהליך כמקשה אחת, ולוודא, בין היתר, *שכל* התהליך לא נכשל בגלל שגיאה, לפעמים במקום סתם משתנים יכולים להיות מופעלים אובייקטים שונים שיכולים ליצור שגיאות בלי קשר ל-CURL בכלל. בקשר לזהות שלי, אני ישתמש בה כאשר מנהלי האתר יחליטו להוסיף למערכת תגובות אפשרויות פרטויות, עריכה ומחיקה לתגובות כמו שמצופה בכל שאתר שמכבד עצמו – לא מתאים לי שזה לוקח את התמונה באופן אוטומטי מחשבון הגוגל שלי, ומדביק אותה באתר בלי לשאול אותי בכלל.

    • זו תגובה שמאד נעים לקרוא ואני שמח שכתבת אותה.

      בנוגע לדוגמה – יכול להיות שציפית לדוגמה יותר מושקעת, כאשר אני בעיקר רציתי להעביר את נושא האימות והאילוץ בכל הנושא של סליקה ומבחינתי הקוד יותר משני כל עוד מבינים את העיקרון.
      הרי בסופו של דבר אני גם לא אוהב להשתמש ב-CURL, פשוט מאמר קודם לכן השתמשתי ב-CURL וזה נראה לי טבעי. יכול להיות שהייתי צריך להשתמש בקוד שממש משתמשים בו – אבל אז עולה השאלה עד כמה לעטוף בקוד את הדוגמה שצריכה בסופו של דבר להיות דוגמה. אבל זה עניין של טעם.

      אתה צודק בנוגע לתהליך, ויכול להיות שאני צריך לכתוב מאמר נפרד שמדבר על try-catch בכללותו ואולי על פרמטרים נוספים באבטחה. לפעמים דברים שנראים לי ולאחרים טריוואליים הם לא כאלו.

      בנוגע לתגובות – המאמר הזה מתפרסם במקור בבלוג שלי, שם יש תגובות מבוססות פייסבוק – אבל יש אנשים שלא סובלים את פייסבוק – אתה תמיד יכול להגיב לי במייל ואשמח לקבל תגובות על כל דבר. בסך הכל כולנו משתפרים מתגובות – במיוחד כאשר מדובר בלימוד ובהדרכה.

      [ועוד הערה קטנה – התמונות נלקחות מ-gravatar ולא מחשבון ג'ימייל]

  8. מאת מוטי:

    !!! עדכון חשוב !!!
    הדרישה החדשה של חברות האשראי היא לעבוד רק ב – redirect. המשמעות היא שהאתר שמבצע את העסקה לא נוגע בפרטי אשראי ולכן פטור מעמידה בתקן PCI.
    לפרטים נוספים אפשר להיכנס ל – telepay.co.il.

  9. מאת גל:

    יש לציין שבמידה ואנו רוצים לבצע סליקה אך לבצע חיוב במועד מאוחר יותר, עדיף להשתמש בטוקן. באופן כללי אני מעדיף את השיטה הזו, כי יותר נוח לבצע מעקב – העברת פרטי האשראי וביצוע החיוב הינם תהליכים נפרדים. אפשר לוודא פרטי אשראי בקלות גם מבלי לבצע חיוב, ושאר הפעולה מתבצעת מול טוקן.
    כמובן שגם כאן אנו צריכים SSL והעברת פרמטים דרך האתר שלנו לחברת הסליקה.
    אגב, ישנן חברות סליקה שמאפשרות לבצע חיובים באתר באמצעות טלפון, שזה גם פתרון נוח.

  10. מאת מישהו:

    האם ניתן לבצע אימות של פרטי כרטיס האשראי (כולל התוקף שלו, למשל במידה ונגנב או בוטל ע"י החברה) גם מבלי לבצע חיוב, ובלי שבכלל סכום החיוב יהיה ידוע בשלב הזה? ואם כן, האם חברות הסליקה או חברות האשראי גובות עמלה כלשהי על האימות הזה?

הרשם לאתר

רק גיקים יכולים ליצור דיון חדש! כדי להפוך לגיק מדופלם, הרשם לאתר.