示例#1
0
 protected function _process(&$np)
 {
     if (empty($this->data_url)) {
         $twitch_url = parse_url($this->stream_url, PHP_URL_PATH);
         $twitch_username = trim($twitch_url, '/');
         $this->data_url = 'https://api.twitch.tv/kraken/streams/' . $twitch_username;
     }
     $return_raw = $this->getUrl();
     if (empty($return_raw)) {
         return false;
     }
     $return = json_decode($return_raw, true);
     $stream = $return['stream'];
     Debug::print_r($stream);
     if (empty($stream)) {
         return false;
     }
     $np['meta']['status'] = 'online';
     $np['meta']['listeners'] = (int) $stream['viewers'];
     $np['on_air']['text'] = $stream['game'];
     if (is_array($stream['preview'])) {
         $np['on_air']['thumbnail'] = $stream['preview']['medium'] . '?t=' . time();
     } else {
         $np['on_air']['thumbnail'] = $stream['preview'] . '?t=' . time();
     }
     return true;
 }
示例#2
0
 public function testAction()
 {
     $this->doNotRender();
     set_time_limit(0);
     ini_set('memory_limit', '-1');
     Debug::setEchoMode();
     Debug::log('Donezo!');
 }
示例#3
0
 public static function import($new_songs, $force = false)
 {
     $db_stats = array('skipped' => 0, 'updated' => 0, 'inserted' => 0, 'deleted' => 0);
     if (empty($new_songs)) {
         return false;
     }
     Debug::startTimer('Import data into database');
     $em = self::getEntityManager();
     $existing_hashes = self::getHashes();
     $existing_ids = self::getIds();
     $unused_hashes = $existing_hashes;
     $song_ids = Song::getIds();
     $i = 0;
     foreach ($new_songs as $song_hash => $processed) {
         if (!in_array($song_hash, $song_ids)) {
             Song::getOrCreate($processed);
         }
         if (isset($existing_hashes[$song_hash])) {
             if ($force && $existing_hashes[$song_hash] == $processed['id']) {
                 $db_stats['updated']++;
                 $record = self::find($processed['id']);
             } else {
                 $db_stats['skipped']++;
                 $record = null;
             }
         } else {
             if (isset($existing_ids[$processed['id']])) {
                 $db_stats['updated']++;
                 $record = self::find($processed['id']);
             } else {
                 $db_stats['inserted']++;
                 $record = new self();
             }
         }
         if ($record instanceof self) {
             $existing_ids[$processed['id']] = $processed['hash'];
             $existing_hashes[$processed['hash']] = $processed['id'];
             $record->fromArray($processed);
             $em->persist($record);
         }
         unset($unused_hashes[$song_hash]);
         $i++;
         if ($i % 200 == 0) {
             $em->flush();
             $em->clear();
         }
     }
     $em->flush();
     $em->clear();
     // Clear out any songs not found.
     $hashes_remaining = array_keys($unused_hashes);
     $db_stats['deleted'] = count($hashes_remaining);
     $em->createQuery('DELETE FROM ' . __CLASS__ . ' e WHERE e.hash IN (:hashes)')->setParameter('hashes', $hashes_remaining)->execute();
     Debug::endTimer('Import data into database');
     Debug::print_r($db_stats);
     return $db_stats;
 }
示例#4
0
 public static function processPodcast(Podcast $record)
 {
     $em = self::getEntityManager();
     $db_stats = array('record' => $record->name, 'updated' => 0, 'inserted' => 0, 'deleted' => 0);
     foreach ($record->sources as $source) {
         if ($source->is_active) {
             $new_episodes = $source->process();
             if (empty($new_episodes)) {
                 continue;
             }
             // Reconcile differences.
             $existing_episodes = array();
             foreach ($source->episodes as $episode) {
                 // Remove duplicate episode.
                 if (isset($existing_episodes[$episode->guid])) {
                     $db_stats['deleted']++;
                     $em->remove($episode);
                 } else {
                     $existing_episodes[$episode->guid] = $episode;
                 }
             }
             foreach ($new_episodes as $ep_guid => $ep_info) {
                 if (isset($existing_episodes[$ep_guid])) {
                     $db_stats['updated']++;
                     $episode = $existing_episodes[$ep_guid];
                 } else {
                     $db_stats['inserted']++;
                     $episode = new PodcastEpisode();
                     $episode->source = $source;
                     $episode->podcast = $record;
                     // Preload banner URL if specified, and if episode is new enough.
                     if ($ep_info['banner_url'] && $ep_info['timestamp'] > time() - 86400 * 14) {
                         PodcastEpisode::getEpisodeRotatorUrl($ep_info, $record, $source);
                     }
                 }
                 $episode->fromArray($ep_info);
                 $em->persist($episode);
                 unset($existing_episodes[$ep_guid]);
             }
             foreach ($existing_episodes as $ep_guid => $ep_to_remove) {
                 $db_stats['deleted']++;
                 $em->remove($ep_to_remove);
             }
         } else {
             foreach ($source->episodes as $episode) {
                 $em->remove($episode);
             }
         }
         $em->flush();
     }
     Debug::print_r($db_stats);
     return true;
 }
示例#5
0
 /**
  * Individual Record Fetching (Retired)
  */
 public static function fetch(Song $song)
 {
     $base_url = 'https://pony.fm/api/v1/tracks/radio-details/';
     $song_hash = self::_getHash($song);
     $url = $base_url . $song_hash . '?client=ponyvillelive';
     \PVL\Debug::log('Hash Search: ' . $url);
     $result_raw = @file_get_contents($url);
     if ($result_raw) {
         $result = json_decode($result_raw, TRUE);
         \PVL\Debug::print_r($result);
         return $result;
     }
     return NULL;
 }
示例#6
0
 public function testAction()
 {
     $this->doNotRender();
     set_time_limit(0);
     ini_set('memory_limit', '-1');
     Debug::setEchoMode();
     // -------- START HERE -------- //
     \PVL\CentovaCast::sync();
     Debug::log('CCast Sync Complete');
     $station = \Entity\Station::getRepository()->findOneBy(array('name' => 'PonyvilleFM'));
     $tracks = \PVL\CentovaCast::fetchTracks($station);
     Debug::print_r($tracks);
     // -------- END HERE -------- //
     Debug::log('Done!');
 }
示例#7
0
 protected static function _querySearch($song)
 {
     $base_url = 'https://eqbeats.org/tracks/search/json';
     $url = $base_url . '?' . http_build_query(array('q' => $song->artist . ' ' . $song->title, 'client' => 'ponyvillelive'));
     Debug::log('Query Search: ' . $url);
     $result = file_get_contents($url);
     if ($result) {
         $rows = json_decode($result, TRUE);
         foreach ($rows as $row) {
             $song_hash = Song::getSongHash(array('artist' => $row['user']['name'], 'title' => $row['title']));
             if (strcmp($song_hash, $song->id) == 0) {
                 return $row;
             }
         }
     }
     return NULL;
 }
示例#8
0
 public static function load($force = false)
 {
     set_time_limit(300);
     Debug::startTimer('Load remote data');
     $remote_url = 'https://bronytunes.com/retrieve_songs.php?client_type=ponyvillelive';
     $result_raw = @file_get_contents($remote_url);
     Debug::endTimer('Load remote data');
     if ($result_raw) {
         $result = json_decode($result_raw, TRUE);
         $new_songs = array();
         foreach ((array) $result as $row) {
             $processed = External::processRemote($row);
             $processed['hash'] = Song::getSongHash($processed);
             $new_songs[$processed['hash']] = $processed;
         }
         return External::import($new_songs, $force);
     }
     return false;
 }
示例#9
0
 public static function run()
 {
     $di = \Phalcon\Di::getDefault();
     $em = $di->get('em');
     // Assemble news items from other sources.
     $news_items_raw = array(self::_runTumblrNews($di), self::_runConventionPromotions($di), self::_runPodcastEpisodes($di), self::_runScheduleItems($di));
     $news_items = array();
     foreach ($news_items_raw as $item_group) {
         $news_items = array_merge($news_items, (array) $item_group);
     }
     // Replace/insert into database.
     $news_stats = array('inserted' => 0, 'updated' => 0, 'deleted' => 0);
     if (!empty($news_items)) {
         $old_news_raw = NetworkNews::fetchAll();
         $old_news = array();
         foreach ($old_news_raw as $old_row) {
             $old_news[$old_row->id] = $old_row;
         }
         // Update or insert items.
         foreach ($news_items as $item) {
             if (isset($old_news[$item['id']])) {
                 $news_stats['updated']++;
                 $record = $old_news[$item['id']];
             } else {
                 $news_stats['inserted']++;
                 $record = new NetworkNews();
             }
             $record->fromArray($item);
             $em->persist($record);
             unset($old_news[$item['id']]);
         }
         // Delete unreferenced items.
         foreach ($old_news as $item_id => $item_to_remove) {
             $news_stats['deleted']++;
             $em->remove($item_to_remove);
         }
         $em->flush();
         // Flush cache of homepage news.
         \DF\Cache::remove('homepage_featured_news');
     }
     \PVL\Debug::print_r($news_stats);
 }
示例#10
0
 protected function _process(&$np)
 {
     $ls_url = parse_url($this->stream_url, PHP_URL_PATH);
     $ls_username = trim($ls_url, '/');
     if (empty($this->data_url)) {
         $this->data_url = 'http://x' . $ls_username . 'x.api.channel.livestream.com/2.0/livestatus.xml';
     }
     $xml = $this->getUrl();
     if (empty($xml)) {
         return false;
     }
     $stream_data = Export::XmlToArray($xml);
     Debug::print_r($stream_data);
     if ($stream_data['channel']['ls:isLive'] && $stream_data['channel']['ls:isLive'] == 'true') {
         $np['meta']['status'] = 'online';
         $np['meta']['listeners'] = (int) $stream_data['channel']['ls:currentViewerCount'];
         $np['on_air']['thumbnail'] = 'http://thumbnail.api.livestream.com/thumbnail?name=' . $ls_username . '&t=' . time();
         $np['on_air']['text'] = 'Stream Online';
         return true;
     }
 }
示例#11
0
 protected function _process(&$np)
 {
     if (empty($this->data_url)) {
         $us_url = parse_url($this->stream_url, PHP_URL_PATH);
         $us_path_parts = explode('/', trim($us_url, '/'));
         $us_username = array_pop($us_path_parts);
         $this->data_url = 'https://api.ustream.tv/channels/' . $us_username . '.json';
     }
     $return_raw = $this->getUrl();
     if (empty($return_raw)) {
         return false;
     }
     $return = json_decode($return_raw, true);
     $channel = $return['channel'];
     Debug::print_r($channel);
     if (empty($channel)) {
         return false;
     }
     $np['meta']['status'] = $channel['status'] == 'live' ? 'online' : 'offline';
     $np['meta']['listeners'] = isset($channel['stats']['viewer']) ? (int) $channel['stats']['viewer'] : 0;
     $np['on_air']['text'] = $channel['title'];
     $np['on_air']['thumbnail'] = $channel['thumbnail']['live'] . '?t=' . time();
     return true;
 }
示例#12
0
 /**
  * Process a podcast source and return remote data from it.
  *
  * @return array|bool
  */
 public function process()
 {
     Debug::log('Processing source: ' . $this->type);
     $source_info = self::getSourceInfo($this->type);
     if (!isset($source_info['adapter'])) {
         Debug::log('No suitable adapter found!');
         return FALSE;
     }
     $source_settings = isset($source_info['settings']) ? $source_info['settings'] : array();
     // Look for new news items.
     $class_name = '\\PVL\\NewsAdapter\\' . $source_info['adapter'];
     $news_items = $class_name::fetch($this->url, $source_settings);
     if (empty($news_items)) {
         Debug::log('No news items found! Adapter: ' . $class_name);
         return FALSE;
     }
     $new_episodes = array();
     foreach ((array) $news_items as $item) {
         $guid = $item['guid'];
         $new_episodes[$guid] = array('guid' => $guid, 'timestamp' => $item['timestamp'], 'title' => self::cleanUpText($item['title']), 'body' => self::cleanUpText($item['body']), 'summary' => self::getSummary($item['body']), 'web_url' => $item['web_url'], 'thumbnail_url' => isset($item['thumbnail_url']) ? $item['thumbnail_url'] : NULL, 'banner_url' => isset($item['banner_url']) ? $item['banner_url'] : NULL);
     }
     Debug::print_r($new_episodes);
     return $new_episodes;
 }
示例#13
0
 public static function run($force_run = false)
 {
     $di = \Phalcon\Di::getDefault();
     $em = $di->get('em');
     $config = $di->get('config');
     // Set up Google Client.
     $gclient_api_key = $config->apis->google_apis_key;
     $gclient_app_name = $config->application->name;
     if (empty($gclient_api_key)) {
         return null;
     }
     $gclient = new \Google_Client();
     $gclient->setApplicationName($gclient_app_name);
     $gclient->setDeveloperKey($gclient_api_key);
     $gcal = new \Google_Service_Calendar($gclient);
     // Prevent running repeatedly in too short of a time (avoid API limits).
     $last_run = Settings::getSetting('schedule_manager_last_run', 0);
     if ($last_run > time() - 60 && !$force_run) {
         return null;
     }
     $schedule_items = array();
     $schedule_records = array();
     $stations = $em->createQuery('SELECT s FROM Entity\\Station s WHERE (s.gcal_url IS NOT NULL AND s.gcal_url != \'\') AND s.is_active = 1')->getArrayResult();
     $active_stations = Utilities::ipull($stations, 'id');
     // Clear all invalid station records.
     $em->createQuery('DELETE FROM Entity\\Schedule s WHERE (s.station_id IS NOT NULL) AND (s.station_id NOT IN (:station_ids))')->setParameter('station_ids', $active_stations)->execute();
     foreach ($stations as $station) {
         if ($station['gcal_url']) {
             $schedule_items[] = array('name' => $station['name'], 'url' => $station['gcal_url'], 'type' => 'station', 'station_id' => $station['id'], 'image_url' => \DF\Url::content($station['image_url']));
         }
     }
     Debug::startTimer('Get Calendar Records');
     // Time boundaries for calendar entries.
     $threshold_start = date(\DateTime::RFC3339, strtotime('-1 week'));
     $threshold_end = date(\DateTime::RFC3339, strtotime('+1 year'));
     foreach ($schedule_items as $item) {
         // Get the "calendar_id" from the URL provided by the user.
         $orig_url_parts = parse_url($item['url']);
         $url_path_parts = explode('/', $orig_url_parts['path']);
         $calendar_id = urldecode($url_path_parts[3]);
         if (empty($calendar_id)) {
             continue;
         }
         // Call the external Google Calendar client.
         try {
             $all_events = $gcal->events->listEvents($calendar_id, array('timeMin' => $threshold_start, 'timeMax' => $threshold_end, 'singleEvents' => 'true', 'orderBy' => 'startTime', 'maxResults' => '300'));
         } catch (\Exception $e) {
             continue;
         }
         // Process each individual event.
         foreach ($all_events as $event_orig) {
             $title = $event_orig->summary;
             $body = $event_orig->description;
             $location = $event_orig->location;
             $web_url = $event_orig->htmlLink;
             $banner_url = null;
             $is_all_day = false;
             $start_time_obj = $event_orig->start;
             if ($start_time_obj->date) {
                 $is_all_day = true;
                 $start_time = strtotime($start_time_obj->date . ' 00:00:00');
             } else {
                 $start_time = strtotime($start_time_obj->dateTime);
             }
             $end_time_obj = $event_orig->end;
             if ($end_time_obj->date) {
                 $is_all_day = true;
                 $end_time = strtotime($end_time_obj->date . ' 00:00:00');
             } elseif ($end_time_obj) {
                 $end_time = strtotime($end_time_obj->dateTime);
             } else {
                 $end_time = $start_time;
             }
             // Detect URLs for link.
             if ($body && !$web_url) {
                 preg_match('@((https?://)?([-\\w]+\\.[-\\w\\.]+)+\\w(:\\d+)?(/([-\\w/_\\.]*(\\?\\S+)?)?)*)@', $body, $urls);
                 if (count($urls) > 0) {
                     $web_url = $urls[0];
                 }
             }
             // Detect URLs for photo.
             if ($location) {
                 preg_match('@((https?://)?([-\\w]+\\.[-\\w\\.]+)+\\w(:\\d+)?(/([-\\w/_\\.]*(\\?\\S+)?)?)*)@', $location, $urls);
                 if (count($urls) > 0) {
                     $banner_url = $urls[0];
                 }
             }
             $guid = md5(implode('|', array($event_orig->id, $start_time, $end_time, $title, $location)));
             $schedule_record = array('guid' => $guid, 'type' => $item['type'], 'start_time' => $start_time, 'end_time' => $end_time, 'is_all_day' => $is_all_day, 'title' => $title, 'location' => $location, 'body' => \DF\Utilities::truncateText(strip_tags($body), 300), 'banner_url' => $banner_url, 'web_url' => $web_url);
             \PVL\Debug::print_r($schedule_record);
             $schedule_records[$item['station_id']][$guid] = $schedule_record;
         }
     }
     Debug::endTimer('Get Calendar Records');
     if (count($schedule_records) == 0) {
         Debug::log('Error: No calendar records loaded');
         return;
     }
     // Add/Remove all differential records.
     Debug::startTimer('Sync DB Records');
     foreach ($schedule_records as $station_id => $station_records) {
         $station = Station::find($station_id);
         if ($station_id == 0) {
             $existing_guids_raw = $em->createQuery('SELECT s.guid FROM Entity\\Schedule s WHERE s.station_id IS NULL')->getArrayResult();
         } else {
             $existing_guids_raw = $em->createQuery('SELECT s.guid FROM Entity\\Schedule s WHERE s.station_id = :sid')->setParameter('sid', $station_id)->getArrayResult();
         }
         $existing_guids = array();
         foreach ($existing_guids_raw as $i) {
             $existing_guids[] = $i['guid'];
         }
         $new_guids = array_keys($station_records);
         $guids_to_delete = array_diff($existing_guids, $new_guids);
         if ($guids_to_delete) {
             $em->createQuery('DELETE FROM Entity\\Schedule s WHERE s.guid IN (:guids)')->setParameter('guids', $guids_to_delete)->execute();
         }
         $guids_to_add = array_diff($new_guids, $existing_guids);
         if ($guids_to_add) {
             foreach ($guids_to_add as $guid) {
                 $schedule_record = $station_records[$guid];
                 $record = new Schedule();
                 $record->station = $station;
                 $record->fromArray($schedule_record);
                 $em->persist($record);
             }
         }
         $em->flush();
         $em->clear();
     }
     Debug::endTimer('Sync DB Records');
     Settings::setSetting('schedule_manager_last_run', time());
 }
示例#14
0
 /**
  * Process a single video stream's NowPlaying info.
  *
  * @param StationStream $stream
  * @param Station $station
  * @return array Structured NowPlaying Data
  */
 public static function processVideoStream(StationStream $stream, Station $station, $force = false)
 {
     $current_np_data = (array) $stream->nowplaying_data;
     if (!$force && NOWPLAYING_SEGMENT % 2 == 0 && !empty($current_np_data)) {
         return $current_np_data;
     }
     // Process stream.
     $custom_class = Station::getStationClassName($station->name);
     $custom_adapter = '\\PVL\\VideoAdapter\\' . $custom_class;
     $np = StationStream::api($stream);
     if (class_exists($custom_adapter)) {
         $np_adapter = new $custom_adapter($stream, $station);
         $stream_np = $np_adapter->process();
     } else {
         $adapters = array(new \PVL\VideoAdapter\Livestream($stream, $station), new \PVL\VideoAdapter\TwitchTv($stream, $station), new \PVL\VideoAdapter\UStream($stream, $station), new \PVL\VideoAdapter\StreamUp($stream, $station));
         foreach ($adapters as $np_adapter) {
             if ($np_adapter->canHandle()) {
                 $stream_np = $np_adapter->process();
                 break;
             }
         }
     }
     if (!empty($stream_np)) {
         $np = array_merge($np, $stream_np);
         $np['status'] = isset($np['meta']['status']) ? $np['meta']['status'] : 'offline';
         Debug::log('Adapter Class: ' . get_class($np_adapter));
         Debug::print_r($np);
     } else {
         $np['on_air'] = array('text' => 'Stream Offline');
         $np['meta'] = array('status' => 'offline', 'listeners' => 0);
         $np['status'] = 'offline';
     }
     $stream->nowplaying_data = $np;
     return $np;
 }
示例#15
0
 public static function syncLong($force = false)
 {
     self::initSync(1800);
     // Sync analytical and statistical data (long running).
     Debug::runTimer('Run analytics manager', function () {
         AnalyticsManager::run();
     });
     // Update convention archives.
     Debug::runTimer('Run convention archives manager', function () {
         ConventionManager::run();
     });
     /*
     // Clean up old API calls.
     Debug::runTimer('Run API call cleanup', function() {
         ApiCall::cleanUp();
     });
     */
     // Clean up old song history entries.
     Debug::runTimer('Run song history cleanup', function () {
         SongHistory::cleanUp();
     });
     // Sync the BronyTunes library.
     Debug::runTimer('Run BronyTunes sync', function () {
         Service\BronyTunes::load();
     });
     // Sync the Pony.fm library.
     Debug::runTimer('Run Pony.fm sync', function () {
         Service\PonyFm::load();
     });
     // Sync the EqBeats library.
     Debug::runTimer('Run EqBeats sync', function () {
         Service\EqBeats::load();
     });
     Settings::setSetting('sync_slow_last_run', time());
 }
示例#16
0
 public function syncAction()
 {
     $this->acl->checkPermission('administer all');
     $this->doNotRender();
     \PVL\Debug::setEchoMode(TRUE);
     \PVL\Debug::startTimer('sync_task');
     $type = $this->getParam('type', 'nowplaying');
     switch ($type) {
         case "long":
             \PVL\SyncManager::syncLong();
             break;
         case "medium":
             \PVL\SyncManager::syncMedium();
             break;
         case "short":
             \PVL\SyncManager::syncShort();
             break;
         case "nowplaying":
         default:
             $segment = $this->getParam('segment', 1);
             define('NOWPLAYING_SEGMENT', $segment);
             \PVL\SyncManager::syncNowplaying(true);
             break;
     }
     \PVL\Debug::endTimer('sync_task');
     \PVL\Debug::log('Sync task complete. See log above.');
 }
示例#17
0
 /**
  * Send an individual notification.
  *
  * @param string $message The main message body of the tweet.
  * @param null $url URL to reference as a link in the tweet.
  * @param null $image URL or filesystem path of an image to reference.
  * @param bool $force Trigger a notification even in development mode.
  * @return bool
  */
 public static function notify($message, $url = null, $image = null, $force = false)
 {
     static $twitter;
     \PVL\Debug::print_r(func_get_args());
     // Suppress notifications for non-production applications.
     if (DF_APPLICATION_ENV != "production" && !$force) {
         return false;
     }
     // Send through Notifico hook.
     $payload = $message . ' - ' . $url;
     \PVL\Service\Notifico::post($payload);
     // Send through Twitter.
     if (!$twitter) {
         $di = \Phalcon\Di::getDefault();
         $config = $di->get('config');
         $twitter_config = $config->apis->twitter->toArray();
         $twitter = new \tmhOAuth($twitter_config);
     }
     $message_length = 140;
     if ($url) {
         $message_length -= 23;
     }
     if ($image) {
         $message_length -= 23;
     }
     // Post t.co URLs directly instead of pulling down data.
     if (stristr($image, 't.co') !== FALSE) {
         $url .= ' ' . $image;
         $image = NULL;
     }
     // Cut off the URL
     $tweet = \DF\Utilities::truncateText($message, $message_length);
     if ($url) {
         $tweet .= ' ' . $url;
     }
     if ($image) {
         $image_data = base64_encode(@file_get_contents($image));
         if (!empty($image_data)) {
             $twitter->request('POST', 'https://upload.twitter.com/1.1/media/upload.json', array('media' => $image_data));
             \PVL\Debug::print_r($twitter->response['response']);
             $image_response = @json_decode($twitter->response['response'], true);
             if (isset($image_response['media_id_string'])) {
                 $media_id = $image_response['media_id_string'];
                 $twitter->request('POST', 'https://api.twitter.com/1.1/statuses/update.json', array('status' => $tweet, 'media_ids' => array($media_id)));
                 \PVL\Debug::print_r($twitter->response['response']);
             }
             return true;
         }
     }
     $twitter->request('POST', 'https://api.twitter.com/1.1/statuses/update.json', array('status' => $tweet));
     \PVL\Debug::print_r($twitter->response['response']);
     return true;
 }
示例#18
0
文件: Curl.php 项目: Lavoaster/PVLive
 /**
  * Submit a URL request with a specified cache lifetime.
  *
  * @param null $c_opts
  * @param int $cache_time
  * @return string
  */
 public static function request($c_opts = null)
 {
     // Compose cURL configuration array.
     if (is_null($c_opts)) {
         $c_opts = array();
     } elseif (!is_array($c_opts)) {
         $c_opts = array('url' => $c_opts);
     }
     $c_defaults = array('method' => 'GET', 'useragent' => 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2) Gecko/20070219 Firefox/2.0.0.2', 'timeout' => 10);
     $c_opts = array_merge($c_defaults, $c_opts);
     Debug::log('cURL Outgoing Request: ' . $c_opts['url']);
     Debug::startTimer('Make cURL Request');
     $postfields = false;
     if (!empty($c_opts['params'])) {
         if (strtoupper($c_opts['method']) == 'POST') {
             $postfields = $c_opts['params'];
         } else {
             $c_opts['url'] = $c_opts['url'] . '?' . http_build_query($c_opts['params']);
         }
     }
     // Start cURL request.
     $curl = curl_init($c_opts['url']);
     // Handle POST support.
     if (strtoupper($c_opts['method']) == 'POST') {
         curl_setopt($curl, CURLOPT_POST, true);
     }
     if (!empty($c_opts['referer'])) {
         curl_setopt($curl, CURLOPT_REFERER, $c_opts['referer']);
     }
     if ($postfields) {
         curl_setopt($curl, CURLOPT_POSTFIELDS, $postfields);
     }
     curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
     curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, $c_opts['timeout']);
     curl_setopt($curl, CURLOPT_TIMEOUT, $c_opts['timeout']);
     curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
     curl_setopt($curl, CURLOPT_USERAGENT, $c_opts['useragent']);
     curl_setopt($curl, CURLOPT_FOLLOWLOCATION, TRUE);
     curl_setopt($curl, CURLOPT_MAXREDIRS, 3);
     // Custom DNS management.
     curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
     curl_setopt($curl, CURLOPT_DNS_CACHE_TIMEOUT, 600);
     // Set custom HTTP headers.
     if (!empty($c_opts['headers'])) {
         curl_setopt($curl, CURLOPT_HTTPHEADER, $c_opts['headers']);
     }
     $return_raw = Utilities::curl_exec_utf8($curl);
     // End cURL request.
     Debug::endTimer('Make cURL Request');
     // Log more detailed information to screen about resolution times.
     $conn_info = curl_getinfo($curl);
     $important_conn_info = array('url', 'http_code', 'total_time', 'namelookup_time', 'connect_time', 'pretransfer_time', 'starttransfer_time', 'redirect_time');
     $debug_conn_info = array();
     foreach ($important_conn_info as $conn_param) {
         $debug_conn_info[$conn_param] = $conn_info[$conn_param];
     }
     Debug::print_r($debug_conn_info);
     $error = curl_error($curl);
     if ($error) {
         Debug::log("Curl error: " . $error);
     }
     return trim($return_raw);
 }