: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
$conn->rollbackAndClose();
public function cleanFeed($feedId){
if ($conn->beginTransaction()){
$partOfSql = $conn->parse('WHERE `feed_id` = ?s', $feedId);
$conn->query('DELETE FROM ?n ?p', $this->posts_table_name, $partOfSql);
$conn->query('DELETE FROM ?n ?p', $this->post_media_table_name, $partOfSql);
$this->setCacheInfo($feedId, [ 'last_update' => 0, 'status' => 0 ] );
$conn->rollbackAndClose();
public function cleanByFeedType($feedType){
if ($conn->beginTransaction()){
$feeds = $conn->getCol('SELECT DISTINCT `feed_id` FROM ?n WHERE `post_type` = ?s', $this->posts_table_name, $feedType);
$conn->query("DELETE FROM ?n WHERE `feed_id` IN (?a)", $this->posts_table_name, $feeds);
$conn->query("DELETE FROM ?n WHERE `feed_id` IN (?a)", $this->post_media_table_name, $feeds);
$conn->rollbackAndClose();
* @param $only4insertPartOfSql
public function addOrUpdatePost($only4insertPartOfSql, $imagePartOfSql, $mediaPartOfSql, $common){
$sql = "INSERT INTO ?n SET ?p, ?p ?p ?u ON DUPLICATE KEY UPDATE ?p ?p ?u";
if (false == $this->conn()->query($sql, $this->posts_table_name, $only4insertPartOfSql, $imagePartOfSql, $mediaPartOfSql, $common, $imagePartOfSql, $mediaPartOfSql, $common)){
throw new Exception($this->conn()->getError());
public function updateAdditionalInfo($posts){
foreach ($posts as $post) {
$sql = $conn->parse('UPDATE ?n SET `post_additional` = ?s WHERE `post_id` = ?s AND `feed_id` = ?s AND `post_type` = ?s',
$this->posts_table_name, json_encode($post->additional), $post->id, $post->feed_id, $post->type);
if (false == $conn->query($sql)){
throw new Exception($conn->getError());
public function getCarousel($feed_id, $post_id){
return $this->conn(true)->getAll('SELECT `feed_id`, `post_id`, `media_url`, `media_width`, `media_height`, `media_type` FROM ?n WHERE `feed_id`=?s AND `post_id`=?s',
$this->post_media_table_name, $feed_id, $post_id);
* @param $mediaPartOfSql4carousel
public function addCarouselMedia($feed_id, $post_id, $post_type, $mediaPartOfSql4carousel){
$common['feed_id'] = $feed_id;
$common['post_id'] = $post_id;
$common['post_type'] = $post_type;
$sql = $conn->parse('INSERT INTO ?n SET ?p ?u', $this->post_media_table_name, $mediaPartOfSql4carousel, $common);
if (false == $conn->query($sql)){
throw new Exception($conn->getError());
public function addComments($post_id, $comment){
$sql_insert = "INSERT INTO ?n SET `id` = ?s, `post_id` = ?s, `from` = ?s, `text` = ?s, `created_time` = ?s, `updated_time` = ?s ON DUPLICATE KEY UPDATE ?u";
$result = $this->conn()->query($sql_insert, $this->comments_table_name, $comment->id, $post_id, is_string($comment->from) ? $comment->from : (is_object($comment->from) ? $comment->from->name : 'Facebook user' ), $comment->text, $comment->created_time, $comment->created_time, [ 'updated_time' => $time, 'text' => $comment->text ] );
throw new Exception($this->conn()->getError());
public function removeComments($post_id){
$sql_delete = "DELETE FROM ?n WHERE `post_id` = ?s";
$this->conn()->query($sql_delete, $this->comments_table_name, $post_id);
public function deleteCarousel4Post($feed_id, $post_id){
$sql = "delete from ?n where feed_id = ?s and post_id = ?s";
if (false == $this->conn()->query($sql, $this->post_media_table_name, $feed_id, $post_id)){
throw new Exception($this->conn()->getError());
public function deleteCarousel4Feed($feed_id){
$sql = "delete from ?n where feed_id = ?s";
if (false == $this->conn()->query($sql, $this->post_media_table_name, $feed_id)){
throw new Exception($this->conn()->getError());
public function getIdPosts($feedId){
return $this->conn(true)->getCol('SELECT `post_id` FROM ?n WHERE `feed_id`=?s', $this->posts_table_name, $feedId);
public function getPostsIf($fields, $condition, $order, $offset = null, $limit = null){
$limitPart = ($offset !== null) ? $conn->parse("LIMIT ?i, ?i", $offset, $limit) : '';
$sql = $conn->parse("SELECT ?p FROM ?n post INNER JOIN ?n stream ON stream.feed_id = post.feed_id INNER JOIN ?n cach ON post.feed_id = cach.feed_id WHERE ?p ORDER BY ?p ?p",
$fields, $this->posts_table_name, $this->streams_sources_table_name, $this->cache_table_name, $condition, $order, $limitPart);
return $conn->getAll($sql);
public function getPostsIf2($fields, $condition){
return $this->conn()->getAll("SELECT ?p FROM ?n post INNER JOIN ?n stream ON stream.feed_id = post.feed_id INNER JOIN ?n cach ON post.feed_id = cach.feed_id WHERE ?p ORDER BY post.post_timestamp DESC, post.post_id",
$fields, $this->posts_table_name, $this->streams_sources_table_name, $this->cache_table_name, $condition);
public function countPostsIf($condition){
return $this->conn()->getOne('SELECT COUNT(*) FROM ?n post INNER JOIN ?n stream ON stream.feed_id = post.feed_id INNER JOIN ?n cach ON post.feed_id = cach.feed_id WHERE ?p',
$this->posts_table_name, $this->streams_sources_table_name, $this->cache_table_name, $condition);
public function getLastUpdateHash($streamId){
return $this->getHashIf($this->conn()->parse('stream.`stream_id` = ?s', $streamId));
public function getHashIf($condition){
return $this->conn()->getOne("SELECT MAX(post.creation_index) FROM ?n post INNER JOIN ?n stream ON stream.feed_id = post.feed_id INNER JOIN ?n cach ON post.feed_id = cach.feed_id WHERE cach.boosted = 'nope' AND ?p",
$this->posts_table_name, $this->streams_sources_table_name, $this->cache_table_name, $condition);
public function getLastUpdateTime($streamId){
return $this->conn()->getOne('SELECT MAX(`last_update`) FROM ?n `cach` inner join ?n `st2src` on `st2src`.`feed_id` = `cach`.`feed_id` WHERE `stream_id` = ?s', $this->cache_table_name, $this->streams_sources_table_name, $streamId);
public function getLastUpdateTimeAllStreams(){
return $this->conn()->getIndCol('stream_id', 'SELECT MAX(`last_update`), `stream_id` FROM ?n `cach` inner join ?n `st2src` on `st2src`.`feed_id` = `cach`.`feed_id` GROUP BY `stream_id`', $this->cache_table_name, $this->streams_sources_table_name);
public function deleteEmptyRecordsFromCacheInfo($streamId){
//$this->conn()->query("DELETE FROM ?n where `stream_id`=?s", $this->cache_table_name, $streamId);
public function systemDisableSource($feedId, $enabled){
$values = [ 'system_enabled' => $enabled ];
$values['send_email'] = 0;
return $this->saveSource($feedId, $values);
public function saveSource( $feedId, $values ) {
return LADB::saveFeed($this->conn(), $this->cache_table_name, $feedId, $values);
* @return FALSE|mysqli|resource
* Use \flow\db\LADBManager::saveSource
public function setCacheInfo($feedId, $values){
$sql = 'INSERT INTO ?n SET `feed_id`=?s, ?u ON DUPLICATE KEY UPDATE ?u';
return $this->conn()->query( $sql, $this->cache_table_name, $feedId, $values, $values );
public function setOrders($feedId){
$conn->query('SET @ROW = -1;');//test mysql_query("SELECT @ROW = -1");
return $conn->query('UPDATE ?n SET `rand_order` = RAND(), `smart_order` = @ROW := @ROW+1 WHERE `feed_id`=?s ORDER BY post_timestamp DESC', $this->posts_table_name, $feedId);
public function removeOldRecords($c_count){
$result = $conn->getAll('select count(*) as `count`, `feed_id` from ?n group by `feed_id` order by 1 desc', $this->posts_table_name);
foreach ( $result as $row ) {
$count = (int)$row['count'];
$count = $count - $c_count;
$sub_query = $conn->parse('select max(tmp.`post_timestamp`) from (select `post_timestamp` from ?n where `feed_id` = ?s order by `post_timestamp` limit 0, ?i) as tmp',$this->posts_table_name, $feed, $count);
$sub_query2 = $conn->parse('select tmp2.post_id from ?n as tmp2 where tmp2.post_timestamp <= (?p)', $this->posts_table_name, $sub_query);
$conn->query('delete from ?n where feed_id = ?s and post_id in (?p)', $this->post_media_table_name, $feed, $sub_query2);
$conn->query('delete from ?n where feed_id = ?s and post_timestamp <= (?p)', $this->posts_table_name, $feed, $sub_query);
* @param null $creation_index
public function setPostStatus($status, $condition, $creation_index = null){
$sql = "UPDATE ?n SET `post_status` = ?s";
$sql .= ($creation_index != null) ? ", `creation_index` = " . $creation_index . " ?p" : " ?p";
if (false == $this->conn()->query($sql, $this->posts_table_name, $status, $condition)){
throw new Exception($this->conn()->getError());
public abstract function getLoadCacheUrl($streamId = null, $force = false);
public function registrationCheck(){
if (false !== ($registration_id = $this->getOption('registration_id'))){
if ((false !== ($registration_date = $this->getOption('registration_date'))) &&
(time() > $registration_date + 604800)){
$ch = curl_init( 'https://flow.looks-awesome.com/wp-admin/admin-ajax.php?action=la_check®istration_id=' . $registration_id);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 5000);
curl_setopt($ch, CURLOPT_POST, false);
$result = curl_exec( $ch );
$result = json_decode($result);
if (isset($result->registration_id) && $registration_id == $result->registration_id){
$settings = $this->getGeneralSettings();
$settings = $settings->original();
$current_subscription = $settings['news_subscription'];
$remote_subscription = $result->subscription == "1" ? LASettingsUtils::YEP : LASettingsUtils::NOPE;
if ($remote_subscription != $current_subscription){
$settings['news_subscription'] = $remote_subscription;
$this->setOption('options', $settings, true);
$this->setOption('registration_id', $result->registration_id);
$this->setOption('registration_date', time());
$activated = !empty($registration_id);
private function activate($settings){
$activated = $this->registrationCheck();
$option_name = 'flow_flow_options';
&& isset($settings[$option_name]['company_email']) && isset($settings[$option_name]['purchase_code'])
&& !empty($settings[$option_name]['company_email']) && !empty($settings[$option_name]['purchase_code'])){
$name = isset($settings[$option_name]['company_name']) ? $settings[$option_name]['company_name'] : 'Unnamed';
if (isset($settings[$option_name]['news_subscription']) && !empty($settings[$option_name]['news_subscription'])){
$subscription = $settings[$option_name]['news_subscription'] == LASettingsUtils::YEP ? 1 : 0;
'action' => 'la_activation',
'email' => @$settings[$option_name]['company_email'],
'purchase_code' => @$settings[$option_name]['purchase_code'],
'subscription' => $subscription,
'plugin_name' => $this->plugin_slug
list($result, $error) = $this->sendRequest2lo($post);
$result = json_decode($result);
if (isset($result->registration_id)){
$this->setOption('registration_id', $result->registration_id);
$this->setOption('registration_date', time());
else if (isset($result->error)){
throw new Exception(is_string($result->error) ? $result->error : print_r($result->error, true));
throw new Exception($error);
$registration_id = $this->getOption('registration_id');
$name = isset($settings[$option_name]['company_name']) ? $settings[$option_name]['company_name'] : 'Unnamed';
'action' => 'la_activation',
'registration_id' => $registration_id,
'email' => @$settings[$option_name]['company_email'],
'purchase_code' => @$settings[$option_name]['purchase_code'],
'plugin_name' => $this->plugin_slug
if (isset($_POST['doSubcribe']) && $_POST['doSubcribe'] == 'true'){
$result = $this->sendRequest2lo($post);
$result = json_decode($result[0]);
if (isset($result->registration_id)){
$this->setOption('registration_id', $result->registration_id);
$this->setOption('registration_date', time());
if (!isset($settings[$option_name]['purchase_code']) || empty($settings[$option_name]['purchase_code'])){
$post['purchase_code'] = '';
$this->sendRequest2lo($post);
$this->deleteOption('registration_id');
$this->deleteOption('registration_date');
private function sendRequest2lo($data){
$ch = curl_init( 'https://flow.looks-awesome.com/wp-admin/admin-ajax.php' );
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_TIMEOUT, 60);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 5000);
$result = curl_exec( $ch );
$error = curl_error($ch);
return [ $result, $error ];
private function getStreamFromRequestWithoutErrors(){
$stream = $_POST['stream'];
// cleaning if error was saved in database stream model, can be removed in future, now it's needed for affected users
if ( isset( $stream['error'] ) ) unset( $stream['error'] );
private function checkSecurity() {
if (!current_user_can('manage_options') || !check_ajax_referer( 'flow_flow_nonce', 'security', false ) ) {
die( json_encode( [ 'error' => 'not_allowed' ] ) );
public function getBoostSources(){
$token = $this->getToken();
$response = Request::post(FF_BOOST_SERVER . 'flow-flow/ff', [
'Content-Type: application/x-www-form-urlencoded'
], http_build_query(['action' => 'get_sources', 'token' => $token]));
if ($response->code == 200) {
foreach ($response->body as &$source){
LADB::prepareSource($source);
else if ($this->isExpiredToken($response)){
return $this->getBoostSources();
* @return array|mixed|Response
private function proxyRequest($data){
if (null != ($token = $this->getToken())){
$response = Request::post(FF_BOOST_SERVER . 'flow-flow/ff', [
'Content-Type: application/x-www-form-urlencoded'
], http_build_query($data));
if ($this->isExpiredToken($response)){
$response = $this->proxyRequest($data);
* @return array|false|mixed|string|null
public function getToken( $force = false ) {
$email = $this->getOption('boosts_email');
$domain = $_SERVER['HTTP_HOST'];
$token = $this->getOption('boosts_token');
if ($force || (false == $token)){
$response = Request::post(FF_BOOST_SERVER . 'token', [
'Content-Type: application/form-data'
], ['domain' => $domain, 'email' => $email]);
if ($response->code == 200 && isset($response->body['token']) && is_string($response->body['token'])) {
$token = $response->body['token'];
$this->setOption('boosts_token', $token);
private function isExpiredToken( $response ) {
if ($response->code == 400 &&
((isset($response->body->error) && $response->body->error == 'Provided token is expired.') ||
(isset($response->body['error']) && $response->body['error'] == 'Provided token is expired.'))
$this->deleteOption('boosts_token');
$this->deleteOption('boosts_subscription');