Ostatnimi czasy napisałem skrypt do pobierania pliku z zewnętrznego hostingu na dysk naszego serwera. Pierwszą fazą projektu jest stworzenie kodu, który będzie miał za zadanie zapisać plik do określonej lokalizacji na naszym serwerze:

  function downloadFile ($url, $path) {
    $newfname = $path;
    $file = fopen ($url, "rb");
    if ($file) {
      $newf = fopen ($newfname, "wb");
      if ($newf) {
        while(!feof($file)) {
          fwrite($newf, fread($file, 1024 * 8 ), 1024 * 8 );
        }
      }
      fclose($file);
    }

    if ($newf) {
      fclose($newf);
    }
  }

  downloadFile('http://serwer.pl/paczka_zrodlowa.zip', "/home/www/downloads/plik_docelowy.zip');

Teraz nasuwa się pytanie: jak uruchomić skrypt, aby nie czekać na rezultat jego działania (tzn. jak uruchomić go w tle)? Możemy uruchomić go w tle korzystając z innego skryptu PHP:

system("php -f /home/www/get.php > /dev/null 2>/dev/null &");

bądź zrobić to bezpośrednio od strony powłoki komendą:

php -f /home/www/get.php > /dev/null 2>/dev/null &

Przy tworzeniu aplikacji ściśle powiązanej z Facebook zadałem sobie pytanie – jak sprawdzić, czy adres profilu bądź fanpage wpisanego przez użytkownika jest poprawny? Z pomocą przyszedł FQL i 1 linijka kodu, prościzna. Implementacja z poziomu PHP wygląda mniej więcej tak (pamiętajmy o wcześniejszym załadowaniu klasy Facebook pobranej np. z : GitHub ):

$facebook = new Facebook(array(
  'appId'  => 'nasz appid',
  'secret' => 'nasz secret przypisany do aplikajci',
  'cookie' => true,
));
$res = $facebook->api(array(
  'method' => 'fql.query',
  'query' => 'select url, normalized_url from link_stat where url = "'.$url.'" ;'
));
if(!isset($res[0]['normalized_url'])) { die('Fanpage nie istnieje.'); }

Jeśli adres podanego fanpage jest poprawny, w elemencie normalized_url otrzymamy poprawną wersję do strony. Jeszcze prościej przestawia się sprawa gdy chcemy wyciągnąć np.: ilość like’ów dla wybranej strony. Zapytanie, które powinnyśmy stworzyć może wyglądać tak:

SELECT likes_count FROM link_stat WHERE url = 'adres fanpage';

Z pomocą FQL możemy pobrać dosłownie wszystko – pełna dokumentacja znajduje się tutaj.

Większość sprzedawców na Allegro ma problem z nieuczciwą konkurencją wykupującą ich aukcje. Zadajmy sobie pytanie: jak się przed tym zabezpieczyć? Niestety problem jest dość duży i nie jest łatwo wyłapać konta oszustów. Okazuje się jednak, że jest kilka sposobów na zabezpieczenie się.

1. Wprowadź ograniczenia dla kupujących bez pełnej aktywacji konta – tacy użytkownicy stanowią odłamek społeczności Allegro, są to zazwyczaj konta tworzone do specjalnych celów, takich jak podbijanie aukcji czy ich wykupowanie.

2. Aktualizuj swoją czarną listę – kontrahenci którzy się tam znajdą nie będą mogli dokonywać zakupów na Twoich aukcjach.

3. Korzystaj  z narzędzi dla sprzedających – system Automater udostępnia swoim użytkownikom ogólnie dostępny moduł Czarnej Listy. Gdy ktoś wykupi aukcje sprzedawcy zarejestrowanego w systemie użytkownik zostanie automatycznie dodany do czarnej listy Allegro wszystkich użytkowników serwisu.

4. Zgłaszaj nieuczciwą konkurencję do Obsługi Allegro – ich adresy IP zostaną zapisane co uniemożliwi im ponowną rejestrację w serwisie.

W ramach tego artykułu udostępniam aktualną bazę z identyfikatorami oszustów bądź przechwyconych kont. Pobierz: blacklist.sql. Do pliku dołączona jest struktura tabeli, kolumna userid nas nie interesuje, blockid zawiera zablokowany identyfikator użytkownika, natomiast data przechowuje datę zablokowania w formacie Unix time. Przykładowy plik PHP aktualizujący czarną listę na naszym koncie Allegro znajduje się poniżej:

<?php
    $blocked_struct[0]['user-id'] = '123456789';
    $blocked_struct[0]['user-black-list-note'] = 'Nieuczciwa konkurencja wykupująca aukcje.';
    function AddToBlackList($struct)
    {
      $doAddToBlackList_struct = array(
        "session-handle" => $_SESSION['session_id'],
        $struct);

      try
      {
        $return = parent::__soapCall(doAddToBlackList, $doAddToBlackList_struct);
      }
      catch(SoapFault $e)
      {
        return $e;
      }
    }
   AddToBlackList($blocked_struct);
?>

Z pomocą do tego skryptu przyjdzie nam klasa Allegro WebAPI, którą zamieściłem kilka postów niżej – wystarczy dodać do niej powyższą funkcję.

W dobie Facebook’a warto zainteresować się ułatwieniem dostępu – logowanie i rejestracja – do zasobów naszej strony z wykorzystaniem Facebook’a. Sama integracja od strony PHP jest banalnie prosta, ponieważ Facebook dostarcza nam gotową klasę z funkcjami i czytelną dokumentacją. W pierwszej kolejności należy stworzyć nową aplikację klikając w ten link. Ważne jest aby wpisać poprawny adres domeny, bo tylko z niego będą akceptowane odwołania. Warto od razu zapisać App ID/API Key oraz App Secret – te 2 wartości posłużą nam do uwierzytelnienia. Dodatkowo potrzebna nam będzie klasa, którą można pobrać z https://github.com/facebook/php-sdk .

Rejestracja

Facebook daje nam możliwość pobrania danych kontaktowych do przeciętnej rejestracji, tj. imię i nazwisko, adres mailowy czy miejsce zamieszkania. Utwórzmy plik fbreg.html w którym zamieśmy poniższy kod:

<iframe src="https://www.facebook.com/plugins/registration.php?
             client_id=112884128818286& // nasz App ID
             redirect_uri=http://example.pl/fbregister.php&  // adres do przekierowania formularza
             fields=name,birthday,gender,location,email" // pola które mają się znaleźć w formularzu
        scrolling="auto"
        frameborder="no"
        style="border:none"
        allowTransparency="true"
        width="100%"
        height="330">
</iframe>

Ramka, którą zamieściliśmy ma za zadanie wyświetlenie formularza rejestracyjnego – nic więcej. Wartość redirect_uri powinna być adresem przekierowania przeglądarki do naszego docelowego pliku – fbregister.php, zawartość pliku:

<?php
  define('FACEBOOK_APP_ID', 'uzupelniami swoimi danymi');
  define('FACEBOOK_SECRET', 'uzupelniamy swoimi danymi');
  session_start();
  function parse_signed_request($signed_request, $secret) {
    list($encoded_sig, $payload) = explode('.', $signed_request, 2);
    $sig = base64_url_decode($encoded_sig);
    $data = json_decode(base64_url_decode($payload), true);

    if (strtoupper($data['algorithm']) !== 'HMAC-SHA256') {
      error_log('Unknown algorithm. Expected HMAC-SHA256');
      return null;
   }

    $expected_sig = hash_hmac('sha256', $payload, $secret, $raw = true);
    if ($sig !== $expected_sig) {
      error_log('Bad Signed JSON signature!');
      return null;
    }

    return $data;
  }

  function base64_url_decode($input) {
    return base64_decode(strtr($input, '-_', '+/'));
  }

  if ($_REQUEST) {
    $response = parse_signed_request($_REQUEST['signed_request'], FACEBOOK_SECRET);
    $_SESSION['form']['email'] = $uLogin['registration']['email'];
    $uName = explode(" ", $uLogin['registration']['name']);
    $_SESSION['form']['name'] = $uName[0];
    $_SESSION['form']['fbid'] = $uLogin[user_id];
    $_SESSION['form']['surname'] = $uName[count($uName)-1];
    $uTown = explode(",", $uLogin['registration']['location']['name']);
    $_SESSION['form']['town'] = $uTown[0];
    header('Location: formularz.html');
  }
  } else {
    die('Brak danych');
  }

?>

Jak widać skrypt ma za zadanie zapisać dane potencjalnego użytkownika Facebooka do sesji, a po zakończeniu przekierować użytkownika do pliku formularz.html. Można się domyśleć, że formularz można automatycznie uzupełnić – na przykład imię – wstawiając w element value wartość <?php echo($_SESSION['form']['name']); ?> po uprzednim aktywowaniu sesji poprzez session_start(); . W sesji znajduje się także zmienna $fbid, której zadaniem jest przekazanie ID użytkownika. Warto zapisać tą wartość do bazy danych w tabeli z użytkownikowi.

Logowanie

Funkcjonuje podobnie jak rejestracja, z tym że pobieramy dane za pomocą metod Facebookowej klasy. Pełny kod zamieszczam poniżej.

<?php
  require 'facebook.php'; // sciezka do facebookowej klasy

  $facebook = new Facebook(array(
    'appId'  => 'nasz app id',
    'secret' => 'nasz app secret',
  ));

  $user = $facebook->getUser();
  // user zwraca numer id aktualnie zalogowanego uzytkownika
  if ($user)
  {
    // weryfikacja logowania, sprawdzanie czy w bazie znajduje sie taki facebookowy id
    if($uResult)
      header('Location: gotowe.html');
    else
      header('Location: facebook.html');
  }
  else
  {
    echo('<html><head><meta http-equiv="refresh" content="0; url='.$facebook->getLoginUrl().'"></head></html>'); // jesli nie ma zezwolenia na pobranie danych przekieruj na Facebook
  }
?>

Do prawidłowego funkcjonowania skryptu fblogin.php wymagana jest specjalna kolumna w bazie danych – fbid. Do zmiennej $user zapisywany jest numer ID użytkownika Facebook. Jeśli Facebook nie zwróci tej wartości skrypt przekieruje go na stronę potwierdzenia. Tak więc logowanie odbywa się nie na podstawie hasła, a numeru ID użytkownika. W pliku fblogin.php nie zawarłem funkcji porównywania numeru ID z tym co mamy w bazie z powodu rozbieżności w strukturach.

Przy tworzeniu nowego projektu natknąłem się na problem z kodowaniem znaków w MySQL – znaki polskie zastępowane były ‘?’. Z problemem zdołałem się uporać dopiero po godzinie. Dlaczego? Bazę stworzyłem przy pomocy kreatora w phpMyAdmin z kodowaniem latynowskim (latin1, oficjalnie ISO-8859-1). Serwis został zakodowany w UTF-8. Wydawało mi się, że zmiana kodowania bazy danych i tabeli na unicode w ustawieniach dostępnych z poziomu phpMyAdmin wystarczy. Nic z tego, bo istniejące kolumny nadal zakodowane są w ISO-8859-1.

Jeżeli też miałeś z tym problem, pamiętaj, że zmiana kodowania bazy danych i tabeli nie wystarczy. Wymagany jest eksport całej tabeli do pliku sql, usunięcie z deklaracji każdej kolumny ciągu o kodowaniu w latin1 w notatniku, usunięcie starej tabeli, a następnie import gotowego kodu do MySQL.

W tym artykule pokażę, jak szybko zaimplementować obsługę Allegro do swojego skryptu. Nie powstrzymam się by napisać, że interfejs programistyczny Allegro to jeden z najgorszy API z którymi miałem okazje współpracować.

WebAPI, które udostępnia nam największy serwis aukcyjny w Polsce, służy do wymiany szeregu informacji między aplikacją zewnętrzną a serwerami Allegro. Komunikacja z Allegro opiera się na protokole SOAP. Aby uzyskać połączenie z serwerem potrzebny nam będzie Klucz WebAPI, którego darmową wersję otrzymamy po uprzednim kontakcie z Biurem Obsługi Użytkownika.

Pierwsze co trzeba zrobić to pobrać aktualną wersję komponentu za pomocją metody doQuerySysStatus. Na samym początku naszego projektu najlepiej utworzyć klasę AllegroClient, której rodzicem będzie SoapClient. Pełny kod naszej klasy zamieściłem poniżej.

  class AllegroClient extends SoapClient
  {
    const COUNTRY_ID = '1';
    public $webapi_key = "klucz webapi";
    public $version_key;
    public $session_id;

    function __construct($login, $password)
    {
      try
      {
        parent::__construct('http://webapi.allegro.pl/uploader.php?wsdl');
      }
      catch(SoapFault $e)
      {
        echo('Błąd: '.$e->getMessage()); exit;
      }
      $this->QuerySysStatus(2);
      $result = $this->LoginEnc($login, $password);
      if($result!=true)
        return $result;
      else return true;
    }

    function QuerySysStatus($id)
    {
      $doQuerySysStatus_struct = array(
        "sysvar" => $id,
        "country-id" => self::COUNTRY_ID,
        "webapi_key" => $this->webapi_key
      );

      try
      {
        $doQuerySysStatus_return = parent::__soapCall(doQuerySysStatus, $doQuerySysStatus_struct);
      }
      catch(SoapFault $e)
      {
        echo('Błąd: '.$e->getMessage());
      }
      $this->version_key = $doQuerySysStatus_return['ver-key'];
      return 1;
    }

    function LoginEnc($login, $password)
    {
      global $sql;
      $doLoginEnc_struct = array(
        "user-login" => $login,
        "user-hash-password" => $password,
        "country-code" => self::COUNTRY_ID,
        "webapi-key" => $this->webapi_key,
        "local-version" => $this->version_key
      );

      try
      {
        $doLoginEnc_return = parent::__soapCall(doLoginEnc, $doLoginEnc_struct);
      }
      catch(SoapFault $e)
      {
        return $e->getMessage();
      }
      $this->session_id = $doLoginEnc_return['session-handle-part'];
      return true;
    }
  }

Aby nasza nowa aplikacja poprawnie zalogowała się na konto Allegro musimy stworzyć nowy obiekt. Przykładowy kod zamieszczam poniżej:

$phash = base64_encode(hash("sha256", "mojehaslo", true)); $client = new AllegroClient('mojlogin', $phash);

Analizując kod który stworzyliśmy:

  1. Aplikacja próbuje nawiązać komunikację z Allegro
  2. Gdy wszystko pójdzie dobrze pobieramy aktualną wersję komponentu (funkcja QuerySysStatus) i przypisujemy jej wartość do klasowej zmiennej version_key
  3. W następnej kolejności obiekt próbuje zalogować się na konto Allegro (metoda LoginEnc wymaga hasła hashowanego SHA-256 i base64) – jeśli nie ma żadnych komplikacji identyfikator sesji potrzebny do kolejnych zapytań zapisywany jest do klasowej zmiennej session_id
Stała COUNTRY_ID którą zadeklarowaliśmy z początku skryptu przechowuje identyfikator kraju w którym chcemy pracować – 1 dla polskiej wersji Allegro. W kolejnych odwołaniach (pobranie listy aukcji, wystawianie przedmiotów) potrzebny nam będzie identyfikator sesji ważny 3 godziny od zalogowania. Jeżeli skrypt ma wykonywać z góry określone zadanie to przechowywanie identyfikatora w zmiennej session_id nie jest złym rozwiązaniem. Natomiast jeżeli myślimy o większej aplikacji, głupim pomysłem byłoby logowanie się do Allegro przy każdym odwołaniu. W tym celu najlepiej przyznany identyfikator umieścić w sesji, a logowanie ponawiać tylko co 3 godziny.
© 2011 Jakub Kiczko Suffusion theme by Sayontan Sinha