Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   API приложений и сред (http://www.flasher.ru/forum/forumdisplay.php?f=61)
-   -   загрузка аватарки пользователя vkontakte (http://www.flasher.ru/forum/showthread.php?t=197451)

HorusWM 07.04.2013 18:08

загрузка аватарки пользователя vkontakte
 
Пробовал загрузить во флешку аватар пользователя через Loader и URL loader, но в обоих случаях ошибки безопасности.
Вот эти шаги проделал:
Код AS3:

Security.allowDomain("*");
Security.loadPolicyFile("http://api.vk.com/crossdomain.xml");
 
var context:LoaderContext = new LoaderContext();
context.checkPolicyFile = true;
context.applicationDomain = ApplicationDomain.currentDomain;

В случае с Loader'ом:
Код AS3:

imageLoader = new Loader();
imageLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, ImageLoaded);
 
try
{
        imageLoader.load(new URLRequest(url), context);
}
catch (err:Error)
{
        ui.Print(err.message);
        handler(null);
}
 
private function ImageLoaded(e:Event):void
{
                        var bmp:BitmapData = new BitmapData(imageLoader.width, imageLoader.height, true, 0x00FFFFFF);
                        try
                        {
                                bmp.draw(e.target.content);
                        }
                        catch(err:Error)
                        {
                                // и тут я получаю SecurityError: Error #2122: Security sandbox violation: BitmapData.draw
                        }
}

В случае с URLLoader'ом:
Код AS3:

urlLoader = new URLLoader();
urlLoader.addEventListener(Event.COMPLETE, UrlLoaderComplete);
urlLoader.addEventListener(IOErrorEvent.IO_ERROR, UrlLoaderIOError);
urlLoader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, UrlLoaderSecurityError);
 
срабатывает UrlLoaderSecurityError()

Подскажите, как правильно загрузить аватар пользователя с его страницы в мое iFrame-приложение?

caseyryan 07.04.2013 18:56

Вот этот код надо выкинуть
Код AS3:

Security.allowDomain("*");
Security.loadPolicyFile("http://api.vk.com/crossdomain.xml");

Приложение не находится на домене api.vk.com

HorusWM 07.04.2013 19:29

Только это ничего не меняет, разве что теперь error#2122 сменился на error#2123.

Попробовал вариант описанный тут http://www.flasher.ru/forum/blog.php?b=208 (через Loader.loadBytes(LoaderInfo.bytes)), но LoaderInfo.bytes = null, хотя LoaderInfo.bytesLoaded показывает некое число загруженных байт. Что не так то?

caseyryan 07.04.2013 20:28

А что это за приложение? Чистый swf залитый в контакт или через iframe грузится?

HorusWM 07.04.2013 20:35

Цитата:

Сообщение от caseyryan (Сообщение 1128681)
А что это за приложение? Чистый swf залитый в контакт или через iframe грузится?

iFrame, я дописал в первом посте. Где-то читал, что некоторые заливают на сервер ВК флешку, которая подгружает фото, а затем тянут из нее, но неужели больше никак? Может через js загружать надо?

Сделал через обмен данными с сервером: ссылка на фото отправляется ему, он возвращает массив байт, описывающих изображение. Тему можно закрывать.

carrotoff 09.04.2013 17:27

Присоединяйся

HorusWM 13.04.2013 10:47

Цитата:

Сообщение от carrotoff (Сообщение 1128972)

Подписался)

caseyryan 13.04.2013 13:52

Цитата:

Сообщение от HorusWM (Сообщение 1128682)
Сделал через обмен данными с сервером: ссылка на фото отправляется ему, он возвращает массив байт, описывающих изображение. Тему можно закрывать.

А можно глянуть серверный код который это делает?
Чтобы свой велосипед не изобретать, когда это понадобится

Добавлено через 1 час 34 минуты
Таки сделал велосипед ) Может кому пригодится

Используется 2 класса на клиенте, и небольшой скрипт на сервере
Основной, универсальный пакет для запросов к серверу:
Код AS3:

package client {
 
        import flash.events.Event;
        import flash.events.IOErrorEvent;
        import flash.events.SecurityErrorEvent;
        import flash.net.URLLoader;
        import flash.net.URLLoaderDataFormat;
        import flash.net.URLRequest;
        import flash.net.URLRequestMethod;
        import flash.net.URLVariables;
        import flash.utils.ByteArray;
 
        public class Packet {
 
                public static const HOST:        String                = "http://hostname.com/";
                public static const SCRIPT:        String                = "call.php";
                public static var USER_ID:        String                = "userId";
                public static var PASSWORD:        String                = "pass";
 
 
                private var _callback:                Function        = null;
                private var _isBinary:                Boolean                = false;
 
                /**
                *
                * @param        method имя метода для передачи в параметр method на сервер
                * @param        callback вызывается когда в ответ на запрос приходят данные
                * в случае ошибки игнорируется
                */

                public function Packet(method:String, callback:Function, params:Object = null, isBinary:Boolean = false) {
                        _callback                                = callback;
                        _isBinary                                = isBinary;
                        var loader:        URLLoader        = new URLLoader();
                        loader.addEventListener(Event.COMPLETE, onComplete);
                        loader.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
                        loader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
                        if (!_isBinary) {
                                loader.dataFormat        = URLLoaderDataFormat.VARIABLES;
                        } else {
                                loader.dataFormat        = URLLoaderDataFormat.BINARY;
                        }
                        var vars:URLVariables        = new URLVariables();
                        vars['method']                        = method;
                        vars['pass']                        = PASSWORD;
                        vars['userId']                        = USER_ID;
                        if (params != null) {
                                for (var i:String in params) {
                                        vars[i] = params[i];
                                }
                        }
                        var rand:        String                = "?" + int(Math.random() * 100000);
                        var request:URLRequest        = new URLRequest(Packet.HOST + Packet.SCRIPT + rand);
                        request.method                        = URLRequestMethod.POST;
                        request.data                        = vars;
                        trace(request.data.toString());
                        try {
                                loader.load(request);
                        } catch (e:Error) {
                                trace(e.getStackTrace());
                        }
 
                }
 
                private function onSecurityError(e:SecurityErrorEvent):void {
                        e.target.removeEventListener(Event.COMPLETE, onComplete);
                        e.target.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
                        e.target.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
                }
 
                private function onIOError(e:IOErrorEvent):void {
                        e.target.removeEventListener(Event.COMPLETE, onComplete);
                        e.target.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
                        e.target.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
                }
 
                private function onComplete(e:Event):void {
                        e.target.removeEventListener(Event.COMPLETE, onComplete);
                        e.target.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
                        e.target.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
                        if (!_isBinary) {
                                var data:Object = e.target.data as Object;
                                if (_callback != null) {
                                        _callback.call(null, data);
                                }
                        } else {
                                var byteArray:ByteArray        = e.target.data as ByteArray;
                                if (_callback != null) {
                                        _callback.call(null, byteArray);
                                }
                        }
                }
        }
}

Вспомогательный пакет для загрузки изображения:

Код AS3:

package client {
        import flash.display.Bitmap;
        import flash.display.Loader;
        import flash.events.Event;
        import flash.events.IOErrorEvent;
        import flash.utils.ByteArray;
        import flash.system.LoaderContext;
        /**
        * загружает картинку с любого домена,
        * через отправку запроса своему серверу
        * и получение этой картинки уже от него
        */

        public class ProxiedImage {
 
                private var _callback:        Function        = null;
 
                /**
                * @param        imageUrl прямая ссылка на картинку
                * @param        callback метод с единственным параметром image:Bitmap
                */

                public function ProxiedImage(imageUrl:String, callback:Function) {
                        _callback        = callback;
                        if (_callback == null) {
                                throw new ArgumentError("callback cannot be null!");
                        }
                        var packet:Packet = new Packet("getImage", onLoad, { url: imageUrl }, true);
                }
                private function onLoad(params:Object):void {
                        if (_callback == null) return;
                        var imageBytes:        ByteArray        = params as ByteArray;
                        var loader:                Loader                = new Loader();
                        loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
                        loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onComplete);
                        try {
                                var context:LoaderContext = new LoaderContext(true);
                                loader.loadBytes(imageBytes, context);
                        } catch (e:Error) {
                                loader.contentLoaderInfo.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
                                loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onComplete);
                        }
 
                }
 
                private function onComplete(e:Event):void {
                        e.target.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
                        e.target.removeEventListener(Event.COMPLETE, onComplete);
                        var image:Bitmap = e.target.content as Bitmap;
                        _callback.call(null, image);
                }
 
                private function onIOError(e:IOErrorEvent):void {
                        e.target.removeEventListener(IOErrorEvent.IO_ERROR, onIOError);
                        e.target.removeEventListener(Event.COMPLETE, onComplete);
                }
        }
}

Ну и php скрипт, который грузит картинку и возвращает байты
PHP код:

$method = $_POST['method'];
if (
$method == "getImage") {
    
$url    = $_POST['url'];
           
$url_reg = "/(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/";
    if (
preg_match($url_reg, $url)) {
        
$file    = file_get_contents($url);
        echo 
$file;
    }
    
} 

Используется все просто.
там, где надо загрузить картинку с другого домена, создаем метод, в который будет возвращаться картинка:

Код AS3:

 
private function onImageLoaded(image:Bitmap):void {
      addChild(image); // вуаля, картинка добавлена
}

и отправляем запрос на загрузку картинки серверу
Код AS3:

var pi:ProxiedImage = new ProxiedImage("http://example.com/image.jpg", onImageLoaded);

Все, после загрузки картинка передастся как аргумент созданному методу

HorusWM 13.04.2013 17:44

У нас немножко по-другому:
Есть отдельный сайт со страницей-генератором на нем, типа http://НекийСайт.com/Default.aspx?img=, который мы передаем как путь +url аватарки для загрузки как параметр. Т.е., выглядит примерно так:
Код AS3:

url = "http://НекийСайт.com/Default.aspx?img=" +"http://cs416319.vk.me/бла-бла-бла.jpg";
imageLoader.load(new URLRequest(url), context);

Страница формирует изображение по переданному параметру и отдает его в наш загрузчик, все) К этой странице может обращаться большое кол-во пользователей без опасности нагрузки на сервер приложения. Загружать можно любые изображения, нужны только прямые ссылки на них.
Скрипт страницы (там 5-10 строк, в общем-то) и длл сейчас выковырять не могу, серверный программист не на месте.

Кстати, caseyryan, у вас ошибка безопасности не вылезает там без LoaderContext?

caseyryan 13.04.2013 18:55

Цитата:

Кстати, caseyryan, у вас ошибка безопасности не вылезает там без LoaderContext?
Да, верно, про него забыл ). Но в принципе, добавить не проблема.
Цитата:

К этой странице может обращаться большое кол-во пользователей без опасности нагрузки на сервер приложения.
А картинка грузится на сам сервер?

HorusWM 13.04.2013 21:22

Цитата:

Сообщение от caseyryan (Сообщение 1129693)
А картинка грузится на сам сервер?

Изображение загружается в саму флешку. Другими словами, мы просто выполняем обычную загрузку через Loader, только урл составляем из 2х частей - ссылки на страницу +в качестве параметра страницы ссылку, полученную на изображение от апи (ну или еще откель).

caseyryan 13.04.2013 23:17

Хм. Интересно все-таки, как это происходит на сервере? Ни разу с этим не сталкивался. Но хорошо бы свой сервер избавить от необходимости загружать картинки

HorusWM 13.04.2013 23:31

вот код, веб-сервер при первом запуске компилирует его в длл:
Код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

public partial class _Default : System.Web.UI.Page
{
    protected override void OnPreInit(EventArgs e)
    {
       
        Response.Clear();
        Response.ClearContent();
        Response.ClearHeaders();
        base.OnPreInit(e);
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        Response.ClearHeaders();
        Response.Clear();

        if (Server.HtmlEncode(Request.QueryString["img"]) != null)
        {
            System.Net.WebClient wc = new System.Net.WebClient();

            byte [] b = wc.DownloadData(Server.HtmlEncode(Request.QueryString["img"]));

            Response.BinaryWrite(b);
        }
        else
        {
            Response.WriteFile("./1.jpg");
        }
        Response.End();
    }
}

Да, на этом сайте должен лежать кроссдоменник, раздающий нужные политики.

caseyryan 13.04.2013 23:54

Ну то есть картинку он все-таки через себя шлет, судя по
Код:

Response.WriteFile("./1.jpg");

HorusWM 13.04.2013 23:58

Цитата:

Сообщение от caseyryan (Сообщение 1129730)
Ну то есть картинку он все-таки через себя шлет

Этот скрипт не используется на сервере приложения, он кладется на сайт, который потом раздает сгенерированные этим кодом страницы с изображениями. Все действия выполняет созданная веб-сервером длл.

caseyryan 14.04.2013 00:10

Да я не об этом. А о том что трафик все равно через сервер идет. Я сначала подумал что картинке просто каким-то образом подменяется адрес, и флешка думает что она грузит ее с другого домена, хотя на самом деле с того же

HorusWM 14.04.2013 00:36

Цитата:

Сообщение от caseyryan (Сообщение 1129733)
Да я не об этом. А о том что трафик все равно через сервер идет. Я сначала подумал что картинке просто каким-то образом подменяется адрес, и флешка думает что она грузит ее с другого домена, хотя на самом деле с того же

Что-то я не уловлю ход вашей мысли, через какой сервер) Флешка грузит изображение с того домена, на котором страница. Пишется бинарник Response.BinaryWrite(b) и отдается флешу. Если ссылка неверная или приходит что-то не являющееся картинкой, то пишется и отдается пустышка Response.WriteFile("./1.jpg")

caseyryan 14.04.2013 10:51

Цитата:

Что-то я не уловлю ход вашей мысли, через какой сервер)
Ну сайт то где находится? В вакууме? Он же по-любому на каком-то сервере

HorusWM 14.04.2013 15:43

Цитата:

Сообщение от caseyryan (Сообщение 1129767)
Ну сайт то где находится? В вакууме? Он же по-любому на каком-то сервере

Не, ну так это понятно, что на каком-то - все изображения с каких сайтов грузятся, которые на каких-то серверах) В данном случае просто не затрагивается сервер приложения, трафик идет не через него и нет надобности пилить java-извороты на странице флешки +сама загрузка в 4-5 строк кода с учетом слушателей. Кроме того, загружать так изображения можно и с классников, и фейсбука, не пробовал еще, но препятствий не вижу.

caseyryan 14.04.2013 19:38

Цитата:

Не, ну так это понятно, что на каком-то - все изображения
Я это к тому, что все равно канал забивается трафиком на все эти картинки. Не кретично конечно, но сначала вообще была мысль что каким-то образом удается обмануть флеш плеер, подсунув ему левый адрес )
А так мой вариант почти то же самое делает. Просто ссылка на картинку ему оправляется пост запросом, и он ее тут же загружает и отдает флешке. Для одной картинки трафик в двойном размере. Но хоть так )

HorusWM 14.04.2013 20:20

Так а какая разница, тянет ли флеш с соцсети или с другого сайта? В этом случае канал всегда будет загружен, никак тут не выкрутишься - картинка-то экстернально подгружается.

caseyryan 14.04.2013 21:10

я о канале сервера
сервер будет все эти картинки для всех пользователей через себя пропускать

HorusWM 15.04.2013 03:33

Не страшно, за трафик платить не надо) Чтобы там получалось что-то страшное, надо, чтобы качались фотогалереи сотнями пользователей, а так только разовая подгрузка маленькой аватарки, ну может еще несколько аватарок друзей.

PainKiller 16.04.2013 11:09

Спасибо всем отписавшимся в этой ветке, код ценный, пригодится

Mirror13 30.04.2013 23:11

Если это поможет, самый быстрый способ пропустить картинку через свой сервер - проксирование на nginx'е. Не нужно выполнять никакие скрипты, нагружая таким образом сервер, нужно только настроить прокси:

Код:

    server {
        server_name proxy.example.com;

        #...
        #Разные параметры
        #...

        resolver 8.8.8.8;
        location ~ ^/p/vk.com/(.+?)\.(vk\.com|vk\.me|userapi\.com)/(.+) {
                proxy_pass http://$1.$2/$3?$query_string;
                proxy_set_header  X-Real-IP $remote_addr;
                proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

Так же nginx умеет кэшировать запросы, так что, вероятно, можно еще и кэшировать картинки у себя, чтобы сократить трафик.

caseyryan 01.05.2013 09:53

интересная штука, надо будет разобраться


Часовой пояс GMT +4, время: 09:13.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.