Pobranie treści strony niczym Facebook – PHP / jQuery

pobranie-tresci-strony-niczym-facebook-php-jquery

Z pewnością wszyscy widzieli i znają sposób dodawania adresów URL do naszych statusów na Facebooku lub Google+. Mam oczywiście na myśli sytuację, gdy po chwili od wklejenia adresu URL w okno, gdzie tworzymy nasz status sprarsowana zostaje i pobrana treść ze strony, której adresu użyliśmy. Jest to zarazem efektowne i bardzo użyteczne, bo od razu widzimy zajawkę informacji, która kryje się pod danym URL. Pokażę Wam dzisiaj prosty sposób, który wykorzystuje język PHP i bibliotekę  jQuery wraz z zapytaniem Ajax. Już dawno przymierzałem się do podobnego wpisu i wreszcie finalnie mogę go Wam przedstawić.

Zacznijmy od obsługi pola, gdzie użytkownik podaje swój adres URL. Obsługiwać będzie je oczywiście kilka linijek kodu w jQuery, gdzie w pierwszej kolejności sparsować musimy wprowadzoną treść oraz sprawdzić istnienie w niej poprawnego adresu URL, a następnie wykonać zapytanie Ajax do skryptu w języku PHP.

Pobieramy treść

$(document).ready(function() {
    var getUrl = $('#get_url') // url to extract from text field
        match_url = /\b(https?):\/\/([\-A-Z0-9.]+)(\/[\-A-Z0-9+&@#\/%=~_|!:,.;]*)?(\?[A-Z0-9+&@#\/%=~_|!:,.;]*)?/i // url to match in the text field
    ;

    getUrl.keyup(function() { // user types url in text field        
        // continue if matched url is found in text field
        if (match_url.test(getUrl.val())) {
            $("#results").hide();
            $("#loading_indicator").show(); // show loading indicator image

            var extracted_url = getUrl.val().match(match_url)[0]; // extracted first url from text filed

            // ajax request to be sent to extract-process.php
            $.post('extract-process.php', {'url': extracted_url}, function(data) {
                extracted_images = data.images;
                total_images = parseInt(data.images.length - 1);
                img_arr_pos = total_images;

                if (total_images > 0) {
                    inc_image = '<div class="extracted_thumb" id="extracted_thumb"><img src="' + data.images[img_arr_pos] + '" width="100" height="100"></div>';
                } else {
                    inc_image = '';
                }
                // content to be loaded in #results element
                var content = '<div class="extracted_url">' + inc_image + '<div class="extracted_content"><h4><a href="' + extracted_url + '" target="_blank">' + data.title + '</a></h4><p>' + data.content + '</p><div class="thumb_sel"><span class="prev_thumb" id="thumb_prev"> </span><span class="next_thumb" id="thumb_next"> </span> </div><span class="small_text" id="total_imgs">' + img_arr_pos + ' of ' + total_images + '</span><span class="small_text">  Choose a Thumbnail</span></div></div>';

                // load results in the element
                $("#results").html(content); // append received data into the element
                $("#results").slideDown(); // show results with slide down effect
                $("#loading_indicator").hide(); // hide loading indicator image
            }, 'json');
        }
    });
});

Wybieramy miniaturę

Skrypt w PHP “wypluje” nam takie dane jak tytuł, zajawkę oraz zdjęcie(-a) w formacie JSON. Jeżeli zdjęć jest kilka, to byłoby dobrze dać użytkownikowi wybór konkretnej miniatury.  Zróbmy to.

$(document).ready(function() {
    // user clicks previous thumbail
    $("body").on("click", "#thumb_prev", function(e) {
        if (img_arr_pos > 0)
        {
            img_arr_pos--; // thmubnail array position decrement

            // replace with new thumbnail
            $("#extracted_thumb").html('<img src="'+extracted_images[img_arr_pos]+'" width="100" height="100">');

            // replace thmubnail position text
            $("#total_imgs").html((img_arr_pos)+' of '+total_images);
        }
    });

    // user clicks next thumbail
    $("body").on("click", "#thumb_next", function(e) {
        if (img_arr_pos < total_images)
        {
            img_arr_pos++; // thmubnail array position increment

            // replace with new thumbnail
            $("#extracted_thumb").html('<img src="'+extracted_images[img_arr_pos]+'" width="100" height="100">');

            // replace thmubnail position text
            $("#total_imgs").html((img_arr_pos)+' of '+total_images);
        }
    });
});

HTML

Poniżej dosłownie 5 linijek HTML, który pozwoli użytkownikowi na wklejenie swojego aresu URL.

<div class="extract_url">
    <img id="loading_indicator" src="images/ajax-loader.gif" />
    <textarea id="get_url" placeholder="Enter Your URL here" class="get_url_input" spellcheck="false"></textarea>
    <div id="results"></div>
</div>

Czas na skrypt w PHP

Do pobrania treści z innej strony w naszym skrypcie PHP wykorzystamy PHP Simple HTML DOM Parser, który w niezwykle łatwy sposób pozwala sparsować drzewo DOM na podstawie przekazanego URL. Trzeba nadmienić, że wymaga on PHP w wersji 5+, ale chyba nie powinno być to dla nikogo problemem. Wszystkie zebrane dane są oczywiście zwracane w formacie JSON.

<?php
if (isset($_POST["url"])) {
    $get_url = $_POST["url"];

    // include PHP HTML DOM parser (requires PHP 5 +)
    include_once("include/simple_html_dom.inc.php");

    // get URL content
    $get_content = file_get_html($get_url);

    // get page title 
    foreach ($get_content->find('title') as $element) {
        $page_title = $element->plaintext;
    }

    // get body text
    foreach ($get_content->find('body') as $element) {
        $page_body = trim($element->plaintext);
        $pos = strpos($page_body, ' ', 200); // find the numeric position to substract
        $page_body = substr($page_body, 0, $pos); // shorten text to 200 chars
    }

    $image_urls = array();

    // get all images URLs in the content
    foreach ($get_content->find('img') as $element) {
        // validate image name
        if (!preg_match('/blank.(.*)/i', $element->src) && filter_var($element->src, FILTER_VALIDATE_URL)) {
            $image_urls[] = $element->src;
        }
    }

    // prepare for JSON 
    $output = array('title' => $page_title, 'images' => $image_urls, 'content' => $page_body);
    echo json_encode($output); // output JSON data
}
?>

Tym oto sposobem mamy gotowe rozwiązanie! Poniżej link do pobrania całości.

Pobranie treści strony niczym Facebook – PHP / jQuery

Autopost Facebook w PHP

FacebookWall

W dobie wszechobecnych serwisów społecznościowych jesteśmy w stanie wykorzystywać ich potencjał i zwiększać tym samym ruch na naszych stronach poprzez prowadzenie Fan Page lub tworzenie dedykowanych aplikacji. Największym beneficjentem takich działań jest oczywiście Facebook. Udostępnia on API, które przykładowo pozwala zarządzać naszymi Fan Page. Publikacja informacji oraz dzielenie się nią ze swoimi “fanami” (mam tutaj na myśli oczywiście lubiących naszą stronę) może odbywać się w sposób automatyczny.

Przykładowo – tworzymy wpis na naszej stronie, który zaraz po publikacji ląduje na Fan Page naszej strony na Facebooku. Nie musimy tym samym powtarzać tej czynności ręcznie, a na pewno nie zapomnimy jej wykonać w późniejszym terminie. Tak działa to na przykład u mnie. Publikując nowy wpis na blogu, wysyłany jest on automatycznie na Fan Page na Facebooku: https://www.facebook.com/mrzepinskipl

Dodatkowo – wykorzystując tagi Open Graph umieszczone w kodzie HTML  naszej strony, jesteśmy w stanie sprawić, by publikacja ta miała zakładaną przez nas formę.

  1. Pierwszym krokiem w realizacji naszego zadania będzie utworzenie aplikacji na stronie Facebook Developers (Apps -> Utwórz aplikację). Otrzymamy w ten sposób wymagane dane (app_id oraz app_secret), które wykorzystamy dalej.
  2. Następnie wchodzimy w opcję edycji naszej aplikacji (Edit app) i na stronie, która nam się załaduje musimy uzupełnić wszystkie wymagane dane,  a w szczególności parametr Canvas URL, którym musi być URL naszej strony, która obsługiwać będzie żądania HTTP wysyłane do Facebook.
  3. Wysyłamy pierwszy request do Facebook, w którym podajemy jakie uprawnienia chcielibyśmy uzyskać:
    https://www.facebook.com/dialog/oauth?client_id={app_id}&redirect_uri={redirect_url}&
    scope=manage_pages,offline_access,publish_stream

    , gdzie jako parametry podajemy:

    • app_id = Application ID -> z ustawień aplikacji
    • redirect_url = Canvas URL -> ten sam URL, który podawaliśmy wyżej

    Jeżeli całość przebiegnie poprawnie, to Facebook zwróci nam callback pod wskazany Canvas URL i za pomocą zmiennej $_GET będziemy mogli pobrać parametr code_string, który posłuży nam do wykonania kolejnego requestu.

  4. Kolejny krok, to wysłanie następnego requestu w ramach którego otrzymamy specjalny token. Posłuży on już finalnie do wysłania publikacji na nasz Fan Page wall.
    https://graph.facebook.com/oauth/access_token?client_id={app_id}&redirect_uri={redirect_url}&
    client_secret={app_secret}&code={code_string}
    • app_id = Application ID -> z ustawień aplikacji
    • redirect_url = Canvas URL -> ten sam URL, który podawaliśmy wyżej
    • app_secret = App Secret -> z ustawień aplikacji
    • code_string -> parametr code_string otrzymany w poprzednim requestcie

    W ten właśnie sposób powinniśmy otrzymać od Facebook parametr token.

  5. Pobieramy Facebook PHP SDK.
  6. Możemy w końcu zrealizować nasze zadanie i wysłać POST na nasz Fan Page wall:
    <?php
    require_once("path/to/facebooksdk/src/facebook.php");
    
    $facebook = new Facebook(array(
      'appId' => '{app_id}', // app_id -> z ustawien aplikacji
      'secret' => '{app_secret}', // app_secret -> z ustawien aplikacji
      'cookie' => true,
    ));
    
    // $token - otrzymany w poprzednim zadaniu HTTP
    $post = array(
      'access_token' => $token,
      'message' =>'wiadomosc',
      'name' => 'imieNazwisko',
      'description'=> 'opis',
      'picture' => 'http://static.obrazek.url/',
      'link' => 'http://link.pl/',
      'caption' =>'podpis'
    );
    try {
      $res = $this->tasks->api('/me/feed','POST', $post);
    } catch (Exception $e) {
      echo $e->getMessage();
    }
    ?>

Tym samym publikacja powinna pojawić się na waszym wallu.

Jak sprawdzić za pomocą PHP, czy adres URL oraz email są poprawne i rzeczywiście istnieją?

Jak sprawdzić za pomocą PHP, czy adres URL oraz email są poprawne i rzeczywiście istnieją?

PHP posiada wiele wbudowanych funkcji (file_exist, is_dir), dzięki którym jesteśmy w stanie sprawdzić, czy na przykład konkretny plik istnieje na dysku, ale jak możemy zdalnie sprawdzić, czy dany adres URL, email, czy link do obrazka są poprawne oraz rzeczywiście istnieją? Postaram się to Wam dzisiaj pokazać dzięki kilku kawałkom kodu, które posłużą do konkretnych zadań.

Czy ten obrazek rzeczywiście tam jest?

PHP5 daje nam możliwość sprawdzenia obrazka, który kryje się nam pod konkretnym linkiem. Dzięki takiej funkcji jak GetImageSize jesteśmy w stanie pobrać obrazek trzymany na zdalnym serwerze i dzięki bibliotece GD zainstalowanej na naszej maszynie.

$external_link = 'http://mrzepinski.pl/wp-content/uploads/2012/08/mrzepinski-resized.png';
if (@GetImageSize($external_link)) {
    echo "obrazek istnieje!";
} else {
    echo "nic tam nie ma :(";
}

Powyższy sposób jest jednak mało efektywny. Cały obrazek jest najpierw pobierany na nasz serwer i dopiero wtedy następuje rzeczywiste sprawdzenie rozmiaru obrazka. Stwarza to też pewne zagrożenie bezpieczeństwa, bo przecież dobrze znane są przypadki, że zły kod krył się właśnie pod postacią rozszerzenia pliku, które sugerowałoby zupełnie inne przeznaczenie niżeli próba odpalenia złośliwego kodu i przejęcie kontroli nad funkcjonowaniem naszego systemu lub narobieniem w nim szkód.

Całość możemy jednak wykonać nieco inaczej. Jeżeli nie boimy się używać biblioteki cURL, to nasz kod może wyglądać następująco:

function checkRemoteFile($url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    // nie pobieraj kontentu na serwer
    curl_setopt($ch, CURLOPT_NOBODY, 1);
    curl_setopt($ch, CURLOPT_FAILONERROR, 1);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    if (curl_exec($ch) !== false) {
        return true;
    } else {
        return false;
    }
}

Jeżeli są jednak tacy, którzy boją się używać cURL’a albo zwyczajnie nie mogą, to istnieje jeszcze funkcja file_get_contents, która pozwala nam na pobranie wystarczającej ilości danych z zewnętrznego serwera, by stwierdzić, że link jest poprawny i prowadzi do konkretnego pliku. Wystarczy, że pobierzemy w ten sposób 1 bajt informacji, tak jak w przykładzie poniżej.

function url_exists($url) {
    if (@file_get_contents($url, 0, null, 0, 1)) {
        return 1;
    } else { 
        return 0;
    }
}

Sprawdzamy adres URL

Taką funkcjonalność możemy uzyskać na wiele sposobów, ale nie wszystkie dobre są w każdej sytuacji. Poniżej kilka przykładów.

function url_exists($url) {
    if (strstr($url, "http://")) 
        $url = "http://".$url;
    $fp = @fsockopen($url, 80);

    return !($fp === false);
}

Powyższa metoda jest zdecydowanie szybsza niż funkcja fopen, ale tylko dla adresów z https:// lub nazw domenowych, ponieważ sprawdzając już adres http://example.com?p=231 możemy napotkać na małe problemy wydajnościowe.

Poniższy sposób jest bardziej kompleksowy, ponieważ sprawdza on tylko odpowiedź serwera, a dokładniej przesłane nagłówki.

function url_exists($url) {
     if ((strpos($url, "http")) === false) 
         $url =  "http://".$url;

     return is_array(@get_headers($url));
}

Całość jednak działa tylko dla URL z http:// oraz z PHP5 i nowszym. Możemy ją jednak nieco rozbudować, tak by i starsza wersja PHP nie była dla nas problemem.

function is_valid_url($url) {
    $url = @parse_url($url);
    if (!$url) {
        return false;
    }

    $url = array_map('trim', $url);
    $url['port'] = (!isset($url['port'])) ? 80 : (int)$url['port'];
    $path = (isset($url['path'])) ? $url['path'] : '';
    if ($path == '') {
        $path = '/';
    }

    $path .= (isset($url['query'])) ? "?$url[query] " : '';
    if (isset($url['host']) AND $url['host'] != gethostbyname($url['host'])) {
        if (PHP_VERSION >= 5) {
            $headers = get_headers("$url[scheme]://$url[host]:$url[port]$path ");
        } else {
            $fp = fsockopen($url['host'], $url['port'], $errno, $errstr, 30);
            if (!$fp) {
                return false;
            }
            fputs($fp, "HEAD $path HTTP/1.1rnHost: $url[host]rnrn");
            $headers = fread($fp, 4096);
            fclose($fp);
        }
        $headers = (is_array($headers)) ? implode("n", $headers) : $headers;
        return (bool)preg_match('#^HTTP/.*s+[(200|301|302)]+s#i', $headers);
    }
    return false;
}

Czego się nie robi, by zachować wsteczną kompatybilność :)

Pozostał nam jeszcze jeden sposób

function image_exist($url) {
    return (@fclose(@fopen( $url,  "r ")));
}

, ale wymaga on by zmienna allow_url_fopen była ustawiona na true w naszym pliku konfiguracyjnym PHP (php.ini).

Sprawdzamy adres em@il

Nadszedł czas na sposoby sprawdzenia poprawności i zweryfikowanie adresu email. Tutaj także mamy kilka ścieżek do wyboru.

Jak się okazuje, proces weryfikacji adresu email w dużej mierze zależy także od ustawień konkretnego serwera SMTP. Mamy jednak możliwość sprawdzenia istnienia konkretnej domeny, by zaoszczędzić sobie trochę czasu i od razu eliminować takie nieprawdziwe adresy. Jesteśmy w stanie to osiągnąć poprzez wykorzystanie funkcji PHP, jaką jest checkdnsrr, która – jak wskazuje nam na to jej nazwa – sprawdza rekordy DNS dla danego URL / hosta. Przykład poniżej.

function email_exist($email) {
    list($userid, $domain) = split("@", $email);

    return checkdnsrr($domain, "MX"));
}

Wszystko byłoby dobrze, ale oczywiście pojawia się kolejny problem. Windows do dzisiaj nie wspiera tej funkcji i aby móc z niej skorzystać, musimy ją sobie stworzyć sami, sic!

if (!function_exists('checkdnsrr'))
function checkdnsrr($hostName, $recType = '') {
   if (!empty($hostName)) {
       if ($recType == '') $recType = "MX";
           exec("nslookup -type=$recType $hostName", $result);

       foreach ($result as $line) {
           if (eregi("^$hostName", $line))
                return true;
       }

       return false;
   }

   return false;
}

Kiedy mamy już gotową obsługę dwóch platform (Linux i Windows), przejdźmy teraz do rzeczy właściwej, a mianowicie, sprawdźmy czy dany email jest poprawny oraz zweryfikujmy jego istnienie.

function isValidEmail($email) {
        $emailError = false;
        $email = htmlspecialchars(stripslashes(strip_tags(trim($email))));
        if ($email == " ") { 
            $emailError = true; 
        } elseif (!eregi( "^([a-zA-Z0-9._-])+@([a-zA-Z0-9._-])+.([a-zA-Z0-9._-])([a-zA-Z0-9._-])+ ", $email)) { 
            $emailError = true; 
        } else {
            list($email, $domain) = split("@", $email, 2);
            if (!checkdnsrr($domain, "MX")) { 
                emailError = true; 
            } else {
                $array = array($email, $domain);
                $email = implode("@", $array);
            }
        }
        return !emailError;
}

I to byłoby na tyle. Znacie jeszcze jakieś sposoby na realizację powyżej przedstawionych funkcjonalności? Jeżeli tak, to oczywiście piszcie w komentarzach. Podyskutujemy :)