كنترل پنل             جستجو               پرسشهای متداول            .:: آخرین پست‌های انجمن ::.            لیست اعضا            مدیران سایت             درجات        ورود
فهرست انجمن‌ها -> برنامه‌نويسي تحت وب -> زبان برنامه‌نويسي PHP
پاسخ دادن به این موضوع
اسکریپت چت با استفاده از comet
پست تاریخ: سه‌شنبه 14 بهمن 1393 - 09:08    
bidak
داره كولاك مي‌كنه!
داره كولاك مي‌كنه!


پست: 121
عضو شده در: 29 تیر 1392

blank.gif


امتياز: 1376

عنوان: اسکریپت چت با استفاده از comet خواندن مشخصات فردی ارسال پیام شخصی ارسال email

سلام.
چن روز پیش بسرم زد یه اسکریپت چت با کامت بنویسم که نوشتم.Very Happy
ولی دیگه حوصلم نکشید بیشتر روش کار کنمSurprised

********************************************************
این لینک دمو رو ببنید.
********************************************************

اگه خواستین با دوتا مرورگر بازش کنید با یوزر های مختلف بازش کنید.
یوزرای پیش فرض رو گذاشتم تو صفحه ی لاگین.
مثلا یکی از یوزرها:
یوزرنیم: demo و پسورد: demo

از این لینک هم اسکریپتو دانلود کنید

------------------------------------
بعدا توضیحات مربوط به کدها رو هم میزارم.


این مطلب آخرین بار توسط bidak در یکشنبه 2 فروردین 1394 - 23:12 ، و در مجموع 1 بار ویرایش شده است.

[ وضعيت كاربر: ]

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

پست تاریخ: سه‌شنبه 14 بهمن 1393 - 14:33    
Hamid
مدیريت كل سایت
مدیريت كل سایت


پست: 5379
عضو شده در: 31 اردیبهشت 1384
محل سکونت: -::ساوه::-
iran.gif


امتياز: 47124

عنوان: پاسخ به «اسکریپت چت با استفاده از comet» خواندن مشخصات فردی ارسال پیام شخصی

سلام.
عالیه.
حتماً روال کار رو توضیح بده چون دوستانی که روی تیکفا ۲ کار می‌کنند نیاز به این موضوع خواهند داشت. باید بخش چت زنده با پشتیبان رو هم تعبیه کنن که می‌تونن از ایده‌ی تو استفاده کنن.
به خصوص اینکه چه زمانی و با چه Eventی به سرور متصل می‌شی و پیغام‌های جدید رو می‌خونی...
ممنون.

[ وضعيت كاربر: ]

تشکر کردن از پست  پاسخگویی به این موضوع بهمراه نقل قول 
تشکرها از این پست: bidak (سه‌شنبه 14 بهمن 1393 - 22:30)

پست تاریخ: چهار‌شنبه 15 بهمن 1393 - 02:28    
bidak
داره كولاك مي‌كنه!
داره كولاك مي‌كنه!


پست: 121
عضو شده در: 29 تیر 1392

blank.gif


امتياز: 1376

عنوان: پاسخ به «اسکریپت چت با استفاده از comet» خواندن مشخصات فردی ارسال پیام شخصی ارسال email

خوب برای پیاده سازی این سیستم میتونیم از ajax استفاده کنیم و هر یک یا چند ثانیه با توابعی مثل setinerval یا settimeout عمل آجاکس رو تکرار کنیم و سمت سرور بریم و چک کنیم اگر پیغام جدیدی اومده بود برای کاربر ارسال بشه.
ولی تعداد درخواست های زیادی که از سمت کلاینت فرستاده میشه بار زیادی رو سرور میزاره که باعث اتلاف منابع سرور و عدم کارایی سیستم میشه.
یکی از راه حل های این موضوع تکنولوژی Comet هست.
در کامت وقتی درخواستی با توابع ajax به سمت سرور از سمت کلاینت فرستاده میشه, در سمت سرور فورا پاسخی داده نمیشه و ارتباط باز میمونه و تا زمانی که نتیجه ای رو دریافت کنه این ارتباطو نگه میداریم.
این کارو با یک حلقه ی بینهایت میتونیم اجرا کنیم.البته در هاست های اشتراکی بعد از 30 ثانیه timeout میشه و ما ارتباطو در حد چند ثانیه باز نگه میداریم.
کلیت قضیه این بود.حالا یکی یکی با کد میرم جلو.
---------------------------------
واسه سند یک پیام نیازی به comet نیست و از ajax استفاده میکنیم.چون قراره هر وقت دکمه ی اینتر و یا دکمه ی سند کلیک شد یک پیام در دیتابیس ثبت شود که این اتفاق زمان کلیک کردن کاربر روی دکمه بوجود میاد بنابراین از ajax استفاده میکنیم.

ارسال پیام: - فایل send.js

تابع sendMessage با فشردن دکمه ی enter اجرا میشه:
کد:

function sendMessage()
{
   var qt = '';
   var txt = text = $('#txtedit').val();
   to = 0;

   if(typeof quote != 'undefined' && quote.trim() != '')
   {
      if(text.match(/\[:::\]_.+_\[:::\]/g))
      {
         var rx = /\[:::\]_(.+)_\[:::\]/g;
           var arr = rx.exec(text)[1];
           arr = arr.split('-');
           to = arr[1];
           messageID = arr[2];

         txt = text = text.replace(/\[:::\]_.+_\[:::\]/g, '');
      }
      
      qt = quote.split(':');
      if(qt[1].trim() != '')
      {
         text += '[_::_]' + quote;
         qt = '<div class="qt"><div class="from" style="'+ colorQuote +'">'+ htmlEntities(qt[0]) +':</div>'+ htmlEntities(qt[1]) +'</div>';
      }
      else
      {
         qt = '';
      }

      quote = undefined;
   }

   $('#messageBox').text('');
   $('#txtedit').val('');
   if($('.context').scrollTop() + $('.context').innerHeight() >= $('.context')[0].scrollHeight)
   {
      $(".context").animate({ scrollTop: $('.context')[0].scrollHeight}, 1000);
   }
   if(txt.trim() != '')
   {
      color = $('.me').attr('color');
      txt = htmlEntities(txt);
      txt = convertToImg(txt);
      $('.context').append('<div class="inner quote lfloat" from="no">'+ qt.trim() +'<div class="from" style="color: '+ color +' !important;">Me:</div>'+ txt +'</div>');
      $('#send').attr('disabled', 'disabled');
      $.ajax({
         url: 'http://localhost/chat/display',
         async: true,
         type: "POST",
         data: 'text=' + text.trim() + '&to=' + to,
         cache: false,
         //dataType: 'json',
         success: function (msg) {
            if (msg == 1)
            {
               $('#send').removeAttr('disabled');
            }
         },
         error: function (msg) {
            alert('app has an error!');
         }
      });
   }
}


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

$('.context').append('<div class="inner quote lfloat" from="no">'+ qt.trim() +'<div class="from" style="color: '+ color +' !important;">Me:</div>'+ txt +'</div>');

بعد هم بخش اصلی تابع که عل سند پیام رو انجام میده این قسمت هست:
کد:

$.ajax({
         url: 'http://localhost/chat/display',
         async: true,
         type: "POST",
         data: 'text=' + text.trim() + '&to=' + to,
         cache: false,
         //dataType: 'json',
         success: function (msg) {
            if (msg == 1)
            {
               $('#send').removeAttr('disabled');
            }
         },
         error: function (msg) {
            alert('app has an error!');
         }
      });

text حاوی پیام کاربره و to مشخص میکنه به چه کاربری داره ارسال میشه یعنی اگر صفر نباشد آیدی کاربری که پاسخش رو دادیم ارسال میکنه.
نمایش پیام کاربرو قبل از آجاکس انجام دادم و append کردم.اولش این عمل نمایش پیامو داخل رویداد success گذاشته بوده ولی چون ارتباط comet باز بود و درخواست کاربر pending میموند تا برگرده و این عمل سند انجام بشه که به همین علت مدت زمانی طول میکشید و نمایش پیامی که سند کرده به تاخیر می افتاد, بخاطر همین قبل از ajax قرار دادم که به محض دکمه ی enter روی صفحه ی کاربر پیامش نمایش داده بشه.
در ادامه , تابع ajax درخواستی رو برای آدرس display در صفحه ی index.php ارسال میکنه و در صفحه ی ایندکس این کد اومده:
کد:

if (isset($parts[0]))
      {
         switch ($parts[0])
         {
            case 'save':
               $obj = new Save();
               echo $obj->save();
               break;

            case 'display':
               $obj = new Message(true);
               echo $obj->display();
               break;

            case 'logout':
               session_destroy();
               Base::redirect($config->baseUrl . '/login');
               break;

            case '404':
               exit('Pooof...');
               break;

            default:
               Base::redirect($config->baseUrl . '/404');
               break;
         }

وقتی درخواست ارسال میشه به این خط کد مرسه و آبجکتی از کلاس message ساخته میشه و متد display صدا زده میشه:
کد:

case 'display':
               $obj = new Message(true);
               echo $obj->display();
               break;

نکته: شرط (case) اول , که save هست اضافیه. یادم رفته پاکش کنم.(چون اول دریافت و ارسال در دو کلاس مختلف انجام میشد و به دلیل اینکه درخواست دریافت پیام ها به مدت چند ثانیه pending میموند و عملیات ارسال هم باید منتظر میشد , تصمیم گرفتم عمل دریافت و ارسال رو در یک کلاس و در یک متد به نام display پیاده کنم.بنظرم خوبه اینجا یه stop به درخواست pending بدیم تا درخواست ارسال پیام اجرا بشه Surprised )

در ادامه وارد متد display میشه :
کد:

public function display()
   {
      if(isset($_POST['text']))
      {
         $text = DB::Escape($_POST['text']);
         $time = microtime(true);
         $to_message_id = (isset($_POST['to']) && $_POST['to'] > 0 ? intval($_POST['to']) : 0);
         DB::Query("INSERT INTO `messages` (`user_id`, `to_message_id`, `text`, `timestamp`) VALUES ('{$_SESSION['id']}', '{$to_message_id}', '{$text}', '{$time}')");
         if(DB::AffectedRows() > 0)
         {
            return 1;
         }
         else
         {
            return DB::LastError();
         }
      }

      if(isset($_POST['time']))
      {
         $time = floatval($_POST['time']);
         $current = time();
         $list = '';
         while (time() - $current < 15)
         {
            $result = self::findAll("WHERE (`timestamp` > '{$time}' AND `user_id` != '{$_SESSION['id']}')");
            if(count($result) > 0)
            {
               $result = array_reverse($result);
               $html = '';
               $to = '';
               foreach ($result as $obj)
               {
                  $qt = '';
                  $text = '';
                  if(strpos($obj->text, '[_::_]'))
                  {
                     $array = explode('[_::_]', $obj->text);
                     $text = $array[0];
                     $q = explode(":", $array[1]);
                     $qt = '<div class="qt"><div class="from" style="color: '. ($_SESSION['username'] == trim($q[0]) ? $_SESSION['userColor'] : '#000') .' !important;">'. ($_SESSION['username'] == trim($q[0]) ? 'Me' : Base::HtmlEscape($q[0])) .':</div>'. Base::HtmlEscape($q[1]) .'</div>';
                  }
                  else
                  {
                     $text = $obj->text;
                  }
                  $html .= '<div class="inner quote" from="'. ($_SESSION['id'] == $obj->user_id ? "no" : $obj->user_id . '-' . $obj->message_id) .'">'. $qt .'<div class="from" style="color: '. $obj->color .' !important;">'. Base::HtmlEscape($obj->username) .':</div>'. Base::convertToImg(Base::HtmlEscape($text));
                  $html .= '<div style="height: 20px;"></div>';
                  $html .= '<div class="time">'. Jdf::jdate('H:i:s | l , j F Y', (explode('.', $obj->timestamp)[0])). '</div>';
                  $html .= '</div>';
                  if ($_SESSION['id'] == $obj->to_message_id)
                  {
                     $to .= '<div class="innerMyMessages quote" from="'. $obj->user_id . '-' . $obj->message_id .'">'. $qt .'<div class="from" style="color: '. $obj->color .' !important;">'. Base::HtmlEscape($obj->username) .':</div>'. Base::convertToImg(Base::HtmlEscape($text)) .'</div>';
                  }
               }
               return json_encode(array('message' => $html, 'to' => $to , 'time' => $obj->timestamp, 'onlineUsers' => substr($list, 0, -1)));
            }
            else
            {
               sleep(2);
            }
            $sess = Loader::load('Session');
            $onlineUsers = $sess->onlineUsers();
            foreach ($onlineUsers as $user)
            {
               $list .= $user . '.';
            }
         }
         return json_encode(array('onlineUsers' => substr($list, 0, -1)));
      }
   }

دو تا شرط وجود داره. یکی وجود متغیر text و شرط دیگه وجود متغیر time.
اگر متغیر تکست وجود داشت یعنی کاربر پیامی ثبت کرده.
در قسمت دیتای تابع ajax , ما text رو ارسال کردیم.پس وارد این قسمت از متد میشه:
کد:

if(isset($_POST['text']))
      {
         $text = DB::Escape($_POST['text']);
         $time = microtime(true);
         $to_message_id = (isset($_POST['to']) && $_POST['to'] > 0 ? intval($_POST['to']) : 0);
         DB::Query("INSERT INTO `messages` (`user_id`, `to_message_id`, `text`, `timestamp`) VALUES ('{$_SESSION['id']}', '{$to_message_id}', '{$text}', '{$time}')");
         if(DB::AffectedRows() > 0)
         {
            return 1;
         }
         else
         {
            return DB::LastError();
         }
      }

و عملیات ثبت پیام در دیتابیس انجام میشه.
الان این فکر اومد تو سرم که خوب بود بعد از عملیات insert , بجای return 1 عمل سلکت هم انجام میدادم و نتایج جدید return میکردم.
کل ماجرای سند پیام جدید اینه.بقیه ی کدهایی که در فایل send.js اومده , تجزیه و بررسی متن وارد شده ی کاربره.

-----------------------------------------
توو پست بعدی ادامه میدم


این مطلب آخرین بار توسط bidak در چهار‌شنبه 15 بهمن 1393 - 04:09 ، و در مجموع 2 بار ویرایش شده است.

[ وضعيت كاربر: ]

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

پست تاریخ: چهار‌شنبه 15 بهمن 1393 - 03:54    
bidak
داره كولاك مي‌كنه!
داره كولاك مي‌كنه!


پست: 121
عضو شده در: 29 تیر 1392

blank.gif


امتياز: 1376

عنوان: پاسخ به «اسکریپت چت با استفاده از comet» خواندن مشخصات فردی ارسال پیام شخصی ارسال email

دریافت پیام کاربران در حین چت - فایل display.js

بعد از ورد به صفحه ی چت و لود صفحه تابع displayMessage اجرا میشه:
کد:

$(document).ready(function() {
   $(window).load(displayMessage(lastTimestamp));
});


این تابع یک درخواست به سمت سرور ارسال میکنه و ما در سمت سرور تا زمانی که رکورد جدیدی از دیتابیس پیدا نکنیم حلقه ای رو سمت سرور تکرار میکنیم و پاسخی به سمت کلاینت نمیفرستیم.
به مجض دریافت رکورد جدید , پاسخ به سمت کاربر ارسال میشه و پاسخ دریافت شده در رویداد success بعد از چند بررسی به کاربر نمایش داده میشود و بعد از نمایش پیام های جدید یک وقفه ی چند ثانیه با تابع settimeout ایجاد میکنیم و دوباره تابع displayMessage رو صدا میزنیم تا همین مرحله ها از ابتدا تکرار شوند و درخواستی سمت سرور ارسال شود.
یعنی با کامت request ها و response ها رو به حداقل رسوندیم.

تابع displayMessage:
کد:

function displayMessage(time)
{
   $.ajax({
      url: 'http://localhost/chat/display',
      async: true,
      type: "POST",
      data: 'time=' + time,
      cache: false,
      dataType: 'json',
      success: function (msg) {
         //alert(msg['message']);return;
         if(msg['message'])
         {
            if($('.context').scrollTop() + $('.context').innerHeight() >= $('.context')[0].scrollHeight)
            {
               $(".context").animate({ scrollTop: $('.context')[0].scrollHeight}, 1000);
            }
            $('.context').append(msg['message']);
            if(msg['to'] != '')
            {
               $('.my-messages').append(msg['to']);
            }
            time = msg['time'];
            //alert(time)
         }
         if(msg['onlineUsers'])
         {
            var users = msg['onlineUsers'].split('.'); // point
            var dvUsers = '';
            users = array_unique(users);
            
            $('.users .innerUsers').each(function() {
               dvUsers += $(this).text().trim() + ',';
            });

            dvUsers = dvUsers.split(',');
            dvUsers = dvUsers.filter(function(a){return  a != '';});

            for (var i = 0; i < users.length; i++)
            {
               if($('.users').html().indexOf(users[i]) == -1)
               {
                  $('<div class="innerUsers '+ users[i] +'">'+ users[i] +'</div>').appendTo('.users').fadeIn(1000);
               }

               if(dvUsers.indexOf(users[i]) != -1)
               {
                  delete dvUsers[dvUsers.indexOf(users[i])];
                  dvUsers = dvUsers.filter(function(a){return typeof a !== 'undefined';});
               }
            };

            if(dvUsers.length > 0)
            {
               $.each(dvUsers, function(index, value) {
                  $('.' + value).remove();
               });
            }
         }
         setTimeout(displayMessage, 2000, time);
      },
      error: function (msg) {
         displayMessage(time);
      }
   });
}


-------------------------
این تابع یک time میگیرد.
در واقع مقدار time برابر time آخرین رکوردیست که از دیتابیس فراخوانی شده و نمایش داده شده.
زمانیکه پیج چت را باز میکنیم , در صفحه ی main.php گفته شده 100 پیام آخر داخل دیتابیس , در صفحه نمایش داده شود. و در ادامه ی همین کدهای main.php این کدو گذاشتم:
کد:

<script>
         var lastTimestamp = <?php echo (isset($obj) ? $obj->timestamp : 0); ?>;
         </script>

متغیری در جاواسکریپت تعریف کردم و مقدارشو برابر timestamp آخرین رکورد fetch شده قرار دادم.
این timestamp بعنوان اولین مقدار time و در اولین اجرای تابع displayMessage قرار میگیره.در فراخوانی های بعدی تابع این مقدار جایگزین میشه.
بعد از اجرای displayMessage آجاکس فراخوانی میشه و در خواستی به همان آدرس قبلی یعنی display به صفحه ی index.php ارسال میشه که حاوی دیتای time است.
در صفحه ی index.php و شرط switch بازهم شرط display اجرا میشود.
متد display فراخوانی میشود و از بین دو شرطی که در پست قبل گفتیم , کد شرط وجود time اجرا میشود:
کد:

if(isset($_POST['time']))
      {
         $time = floatval($_POST['time']);
         $current = time();
         $list = '';
         while (time() - $current < 15)
         {
            $result = self::findAll("WHERE (`timestamp` > '{$time}' AND `user_id` != '{$_SESSION['id']}')");
            if(count($result) > 0)
            {
               $result = array_reverse($result);
               $html = '';
               $to = '';
               foreach ($result as $obj)
               {
                  $qt = '';
                  $text = '';
                  if(strpos($obj->text, '[_::_]'))
                  {
                     $array = explode('[_::_]', $obj->text);
                     $text = $array[0];
                     $q = explode(":", $array[1]);
                     $qt = '<div class="qt"><div class="from" style="color: '. ($_SESSION['username'] == trim($q[0]) ? $_SESSION['userColor'] : '#000') .' !important;">'. ($_SESSION['username'] == trim($q[0]) ? 'Me' : Base::HtmlEscape($q[0])) .':</div>'. Base::HtmlEscape($q[1]) .'</div>';
                  }
                  else
                  {
                     $text = $obj->text;
                  }
                  $html .= '<div class="inner quote" from="'. ($_SESSION['id'] == $obj->user_id ? "no" : $obj->user_id . '-' . $obj->message_id) .'">'. $qt .'<div class="from" style="color: '. $obj->color .' !important;">'. Base::HtmlEscape($obj->username) .':</div>'. Base::convertToImg(Base::HtmlEscape($text));
                  $html .= '<div style="height: 20px;"></div>';
                  $html .= '<div class="time">'. Jdf::jdate('H:i:s | l , j F Y', (explode('.', $obj->timestamp)[0])). '</div>';
                  $html .= '</div>';
                  if ($_SESSION['id'] == $obj->to_message_id)
                  {
                     $to .= '<div class="innerMyMessages quote" from="'. $obj->user_id . '-' . $obj->message_id .'">'. $qt .'<div class="from" style="color: '. $obj->color .' !important;">'. Base::HtmlEscape($obj->username) .':</div>'. Base::convertToImg(Base::HtmlEscape($text)) .'</div>';
                  }
               }
               return json_encode(array('message' => $html, 'to' => $to , 'time' => $obj->timestamp, 'onlineUsers' => substr($list, 0, -1)));
            }
            else
            {
               sleep(2);
            }
            $sess = Loader::load('Session');
            $onlineUsers = $sess->onlineUsers();
            foreach ($onlineUsers as $user)
            {
               $list .= $user . '.';
            }
         }
         return json_encode(array('onlineUsers' => substr($list, 0, -1)));
      }

کل کدها به کنار قسمت اصلی کد , حلقه ی while با تکرار به مدت 15 ثانیه هست:
کد:

while (time() - $current < 15)

هر بار که این حلقه اجرا میشود , یک کوئری اجرا میشود:
کد:

$result = self::findAll("WHERE (`timestamp` > '{$time}' AND `user_id` != '{$_SESSION['id']}')");

این کوئری تمام رکوردهایی که timestamp اشون بزرگتر از time ارسالی توسط آجاکس(یعنی time آخرین رکورد نمایش داده شده در صفحه ی کاربر) است رو واکشی میکنه.البته این شرط هم وجود داره که پیام هایی واکشی بشن که فرستندشون خود کاربر نباشن.(چون پیام های خود کاربر به محض سند شدن رو صفحه ی خودش یکبار نمایش داده شده.اینجا فرضو براین گرفتم که یک یوزر با یک مرورگر قراره باز بشه و بصورت همزمان کسی نباید باز کنه.)
میشد شرطو جابجا کرد و اول user_id چک بشه و بعد AND بشه با شرط timestamp. چون اگه شرط user_id برقرار نبود دیگه شرط timestamp اجرا نشه و باعث سرعت بیشتری در کوئری بشه.

خلاصه بعد از عمل fetch کردن اگر رکوردی پیدا شد if اجرا میشه و تمام پیام های جدید واکشی شده بسمت کلاینت return میشن و در success دریافت و نمایش داده میشن و بعد از چند ثانیه دوباره یک درخواست جدید بهمراه آخرین timestamp بسمت سرور فرستاده میشه.
اما اگر رکوردی یافت نشد یعنی پیغامی ثبت نشده , بنابراین else اجرا میشود.
در قسمت else :
کد:

else
            {
               sleep(2);
            }

به مدت دوثانیه وقفه ایجاد کردیم تا به سرور فشار زیادی وارد نشه.
و بعد از else دوباره این حلقه اجرا میشه.
این حلقه در مدت 15 ثانیه ای که تکرار میشه همین روالو ادامه میده.اگر رکوردی پیدا شد ارتباط قطع میشه قطع میشه و پاسخ به سمت کلاینت فرستاده میشود.
اما اگر در مدت 15 ثانیه رکوردی پیدا نشد این اسکریپت به پایان میرسه و تنها تعداد کاربران آنلاینو return میکنه.

یک نکته در مورد time: در اول کار , زمان رو برحسب ثانیه وارد دیتابیس میکردم.ولی در تست هایی که انجام دادم , وقتی سریع و پشت سرهم مثلا عدد 1 تا 9 ارسال میکردم , در نمایش پیام ها قاطی میکرد.بعضی هارو هم جا مینداخت. یعنی در دیتابیس درست درج شده بود ولی در نمایش به مشکل میخورد. واسه همین فیلد timestamp رو double گذاشتم و مقدار تایم هر پیام رو با microtime ذخیره کردم.

---------------------------------
این از کل داستان. Very Happy
توو پست بعدی در مورد حواشی ماجرا توضیج میدم Very Happy

[ وضعيت كاربر: ]

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

پست تاریخ: چهار‌شنبه 15 بهمن 1393 - 10:52    
farzandtork
خوب داره پيش مي‌ره
خوب داره پيش مي‌ره


پست: 78
عضو شده در: 18 دی 1393
محل سکونت: همین حوالی
iran.gif


امتياز: 707

عنوان: پاسخ به «اسکریپت چت با استفاده از comet» خواندن مشخصات فردی ارسال پیام شخصی

برادر خسته نباشی

[ وضعيت كاربر: ]

تشکر کردن از پست  پاسخگویی به این موضوع بهمراه نقل قول 
تشکرها از این پست: bidak (چهار‌شنبه 15 بهمن 1393 - 12:46)


نمایش پستها:                 مشاهده موضوع قبلی :: مشاهده موضوع بعدی  
پاسخ دادن به این موضوع
 

صفحه 1 از 1

تمام زمانها بر حسب GMT + 3.5 Hours می‌باشند
 Related Topics 


 information 

 

پرش به:  
شما نمی توانید در این بخش موضوع جدید پست کنید
شما نمی توانید در این بخش به موضوعها پاسخ دهید
شما نمی توانید موضوع های خودتان را در این بخش ویرایش کنید
شما نمی توانید موضوع های خودتان را در این بخش حذف کنید
شما نمی توانید در این بخش رای دهید


Copyright 2004-2020. All rights reserved.
© by Aftabgardan Cultural Center : Aftab.cc