Example #1
0
 public function getEnabled()
 {
     try {
         $result = Cache::item('foolframe.model.plugins.get_enabled.query')->get();
     } catch (\OutOfBoundsException $e) {
         $result = $this->dc->qb()->select('*')->from($this->dc->p('plugins'), 'p')->where('enabled = :enabled')->setParameter(':enabled', 1)->execute()->fetchAll();
         Cache::item('foolframe.model.plugins.get_enabled.query')->set($result, 3600);
     }
     return $result;
 }
Example #2
0
 /**
  * Adapter for Markdown that caches the result
  *
  * @param string $text The content to parse from MarkDown to HTML
  *
  * @return string The HTML
  */
 public static function parse($text)
 {
     try {
         return Cache::item('foolframe.model.markdown.parse.md5.' . md5($text))->get();
     } catch (\OutOfBoundsException $e) {
         $parsed = M::defaultTransform($text);
         Cache::item('foolframe.model.markdown.parse.md5.' . md5($text))->set($parsed, 900);
         return $parsed;
     }
 }
Example #3
0
 /**
  * @param bool $reload
  * @return array|mixed
  */
 public function load($reload = false)
 {
     $this->profiler->log('Preferences::load Start');
     if ($reload === true) {
         Cache::item('foolframe.model.preferences.settings')->delete();
     }
     $this->modules = $this->config->get('foolz/foolframe', 'config', 'modules.installed');
     try {
         $this->preferences = Cache::item('foolframe.model.preferences.settings')->get();
     } catch (\OutOfBoundsException $e) {
         $preferences = $this->dc->qb()->select('*')->from($this->dc->p('preferences'), 'p')->execute()->fetchAll();
         foreach ($preferences as $pref) {
             // fix the PHP issue where . is changed to _ in the $_POST array
             $this->preferences[$pref['name']] = $pref['value'];
         }
         Cache::item('foolframe.model.preferences.settings')->set($this->preferences, 3600);
     }
     $this->preferences = Hook::forge('Foolz\\FoolFrame\\Model\\Preferences::load#var.preferences')->setObject($this)->setParam('preferences', $this->preferences)->execute()->get($this->preferences);
     $this->profiler->logMem('Preferences $preferences', $this->preferences);
     $this->profiler->log('Preferences::load End');
     $this->loaded = true;
     return $this->preferences;
 }
Example #4
0
 /**
  * Gets a thread
  *
  * @return  \Foolz\Foolslide\Model\Board  The current object
  * @throws  BoardThreadNotFoundException  If the thread wasn't found
  */
 protected function p_getThreadComments()
 {
     $this->profiler->log('Board::getThreadComments Start');
     extract($this->options);
     // determine type
     switch ($type) {
         case 'from_doc_id':
             $query_result = $this->dc->qb()->select('*')->from($this->radix->getTable(), 'r')->leftJoin('r', $this->radix->getTable('_images'), 'mg', 'mg.media_id = r.media_id')->where('thread_num = :thread_num')->andWhere('doc_id > :latest_doc_id')->orderBy('num', 'ASC')->addOrderBy('subnum', 'ASC')->setParameter(':thread_num', $num)->setParameter(':latest_doc_id', $latest_doc_id)->execute()->fetchAll();
             break;
         case 'ghosts':
             $query_result = $this->dc->qb()->select('*')->from($this->radix->getTable(), 'r')->leftJoin('r', $this->radix->getTable('_images'), 'mg', 'mg.media_id = r.media_id')->where('thread_num = :thread_num')->where('subnum <> 0')->orderBy('num', 'ASC')->addOrderBy('subnum', 'ASC')->setParameter(':thread_num', $num)->execute()->fetchAll();
             break;
         case 'last_x':
             try {
                 // we save some cache memory by only saving last_50, so it must always fail otherwise
                 if ($last_limit != 50) {
                     throw new \OutOfBoundsException();
                 }
                 $query_result = Cache::item('foolslide.model.board.getThreadComments.last_50.' . md5(serialize([$this->radix->shortname, $num])))->get();
             } catch (\OutOfBoundsException $e) {
                 $subquery_first = $this->dc->qb()->select('*')->from($this->radix->getTable(), 'xr')->where('num = ' . $this->dc->getConnection()->quote($num))->setMaxResults(1)->getSQL();
                 $subquery_last = $this->dc->qb()->select('*')->from($this->radix->getTable(), 'xrr')->where('thread_num = ' . $this->dc->getConnection()->quote($num))->orderBy('num', 'DESC')->addOrderBy('subnum', 'DESC')->setMaxResults($last_limit)->getSQL();
                 $query_result = $this->dc->qb()->select('*')->from('((' . $subquery_first . ') UNION (' . $subquery_last . '))', 'r')->leftJoin('r', $this->radix->getTable('_images'), 'mg', 'mg.media_id = r.media_id')->orderBy('num', 'ASC')->addOrderBy('subnum', 'ASC')->execute()->fetchAll();
                 // cache only if it's last_50
                 if ($last_limit == 50) {
                     $cache_time = 300;
                     if ($this->radix->archive) {
                         $cache_time = 30;
                         // over 7 days is old
                         $old = time() - 604800;
                         // set a very long cache time for archive threads older than a week, in case a ghost post will bump it
                         foreach ($query_result as $k => $r) {
                             if ($r['timestamp'] < $old) {
                                 $cache_time = 300;
                                 break;
                             }
                         }
                     }
                     Cache::item('foolslide.model.board.getThreadComments.last_50.' . md5(serialize([$this->radix->shortname, $num])))->set($query_result, $cache_time);
                 }
             }
             break;
         case 'thread':
             try {
                 $query_result = Cache::item('foolslide.model.board.getThreadComments.thread.' . md5(serialize([$this->radix->shortname, $num])))->get();
             } catch (\OutOfBoundsException $e) {
                 $query_result = $this->dc->qb()->select('*')->from($this->radix->getTable(), 'r')->leftJoin('r', $this->radix->getTable('_images'), 'mg', 'mg.media_id = r.media_id')->where('thread_num = :thread_num')->orderBy('num', 'ASC')->addOrderBy('subnum', 'ASC')->setParameter(':thread_num', $num)->execute()->fetchAll();
                 $cache_time = 300;
                 if ($this->radix->archive) {
                     $cache_time = 30;
                     // over 7 days is old
                     $old = time() - 604800;
                     // set a very long cache time for archive threads older than a week, in case a ghost post will bump it
                     foreach ($query_result as $k => $r) {
                         if ($r['timestamp'] < $old) {
                             $cache_time = 300;
                             break;
                         }
                     }
                 }
                 Cache::item('foolslide.model.board.getThreadComments.thread.' . md5(serialize([$this->radix->shortname, $num])))->set($query_result, $cache_time);
             }
             break;
     }
     if (!count($query_result) && isset($latest_doc_id)) {
         return $this->comments = $this->comments_unsorted = [];
     }
     if (!count($query_result)) {
         throw new BoardThreadNotFoundException(_i('There\'s no such a thread.'));
     }
     foreach ($query_result as $key => $row) {
         $data = new CommentBulk();
         $data->import($row, $this->radix);
         unset($query_result[$key]);
         $this->comments_unsorted[] = $data;
     }
     unset($query_result);
     foreach ($this->comments_unsorted as $key => $bulk) {
         if ($bulk->comment->op == 0) {
             $this->comments[$bulk->comment->thread_num]['posts'][$bulk->comment->num . ($bulk->comment->subnum == 0 ? '' : '_' . $bulk->comment->subnum)] =& $this->comments_unsorted[$key];
         } else {
             $this->comments[$bulk->comment->num]['op'] =& $this->comments_unsorted[$key];
         }
     }
     $this->profiler->logMem('Board $this->comments', $this->comments);
     $this->profiler->logMem('Board $this', $this);
     $this->profiler->log('Board::getThreadComments End');
     return $this;
 }
Example #5
0
 protected function clearCache()
 {
     // clean up some caches
     Cache::item('foolfuuka.model.board.getThreadComments.thread.' . md5(serialize([$this->radix->shortname, $this->comment->thread_num])))->delete();
     // clean up the 10 first pages of index and gallery that are cached
     for ($i = 1; $i <= 10; $i++) {
         Cache::item('foolfuuka.model.board.getLatestComments.query.' . $this->radix->shortname . '.by_post.' . $i)->delete();
         Cache::item('foolfuuka.model.board.getLatestComments.query.' . $this->radix->shortname . '.by_thread.' . $i)->delete();
         Cache::item('foolfuuka.model.board.getThreadsComments.query.' . $this->radix->shortname . '.' . $i)->delete();
     }
     return $this;
 }
Example #6
0
 /**
  * Send the comment and attached media to database
  *
  * @param Media $media
  * @param array $data extra data
  * @throws CommentSendingDatabaseException
  * @throws CommentSendingBannedException
  * @throws CommentSendingThreadWithoutMediaException
  * @throws CommentSendingSpamException
  * @throws CommentSendingImageInGhostException
  * @throws CommentSendingNoDelPassException
  * @throws CommentSendingThreadClosedException
  * @throws CommentSendingRequestCaptchaException
  * @throws CommentSendingTimeLimitException
  * @throws CommentSendingException
  * @throws CommentSendingTooManyCharactersException
  * @throws \RuntimeException
  * @throws CommentSendingDisplaysEmptyException
  * @throws CommentSendingTooManyLinesException
  * @throws CommentSendingSameCommentException
  * @throws CommentSendingWrongCaptchaException
  * @throws CommentSendingUnallowedCapcodeException
  * @return array error key with explanation to show to user, or success and post row
  */
 public function p_insert(Media $media = null, $data = [])
 {
     if (isset($data['recaptcha_challenge'])) {
         $this->recaptcha_challenge = $data['recaptcha_challenge'];
         $this->recaptcha_response = $data['recaptcha_response'];
     }
     $this->ghost = false;
     $this->ghost_exist = false;
     $this->allow_media = true;
     // some users don't need to be limited, in here go all the ban and posting limitators
     if (!$this->getAuth()->hasAccess('comment.limitless_comment')) {
         // check if the user is banned
         if ($ban = $this->ban_factory->isBanned($this->comment->poster_ip, $this->radix)) {
             if ($ban->board_id == 0) {
                 $banned_string = _i('It looks like you were banned on all boards.');
             } else {
                 $banned_string = _i('It looks like you were banned on /' . $this->radix->shortname . '/.');
             }
             if ($ban->length) {
                 $banned_string .= ' ' . _i('This ban will last until:') . ' ' . date(DATE_COOKIE, $ban->start + $ban->length) . '.';
             } else {
                 $banned_string .= ' ' . _i('This ban will last forever.');
             }
             if ($ban->reason) {
                 $banned_string .= ' ' . _i('The reason for this ban is:') . ' «' . $ban->reason . '».';
             }
             if ($ban->appeal_status == Ban::APPEAL_NONE) {
                 $banned_string .= ' ' . _i('If you\'d like to appeal to your ban, go to the %s page.', '<a href="' . $this->uri->create($this->radix->shortname . '/appeal') . '">' . _i('Appeal') . '</a>');
             } elseif ($ban->appeal_status == Ban::APPEAL_PENDING) {
                 $banned_string .= ' ' . _i('Your appeal is pending.');
             }
             throw new CommentSendingBannedException($banned_string);
         }
     }
     // check if it's a thread and its status
     if ($this->comment->thread_num > 0) {
         try {
             $thread = Board::forge($this->getContext())->getThread($this->comment->thread_num)->setRadix($this->radix);
             $status = $thread->getThreadStatus();
         } catch (BoardException $e) {
             throw new CommentSendingException($e->getMessage());
         }
         if ($status['closed']) {
             throw new CommentSendingThreadClosedException(_i('The thread is closed.'));
         }
         $this->ghost = $status['dead'];
         $this->ghost_exist = $status['ghost_exist'];
         $this->allow_media = !$status['disable_image_upload'];
     }
     foreach (['name', 'email', 'title', 'comment', 'capcode'] as $key) {
         $this->comment->{$key} = trim((string) $this->comment->{$key});
     }
     $this->comment->setDelpass(trim((string) $this->comment->getDelPass()));
     // some users don't need to be limited, in here go all the ban and posting limitators
     if (!$this->getAuth()->hasAccess('comment.limitless_comment')) {
         if ($this->comment->thread_num < 1) {
             // one can create a new thread only once every 5 minutes
             $check_op = $this->dc->qb()->select('*')->from($this->radix->getTable(), 'r')->where('r.poster_ip = :poster_ip')->andWhere('r.timestamp > :timestamp')->andWhere('r.op = :op')->setParameters([':poster_ip' => $this->comment->poster_ip, ':timestamp' => time() - $this->radix->getValue('cooldown_new_thread'), ':op' => true])->setMaxResults(1)->execute()->fetch();
             if ($check_op) {
                 throw new CommentSendingTimeLimitException(_i('You must wait up to %d minutes to make another new thread.', ceil($this->radix->getValue('cooldown_new_thread') / 60)));
             }
         }
         // check the latest posts by the user to see if he's posting the same message or if he's posting too fast
         $check = $this->dc->qb()->select('*')->from($this->radix->getTable(), 'r')->where('poster_ip = :poster_ip')->orderBy('timestamp', 'DESC')->setMaxResults(1)->setParameter(':poster_ip', $this->comment->poster_ip)->execute()->fetch();
         if ($check) {
             if ($this->comment->comment !== null && $check['comment'] === $this->comment->comment) {
                 throw new CommentSendingSameCommentException(_i('You\'re sending the same comment as the last time'));
             }
             $check_time = $this->getRadixTime();
             if ($check_time - $check['timestamp'] < $this->radix->getValue('cooldown_new_comment') && $check_time - $check['timestamp'] > 0) {
                 throw new CommentSendingTimeLimitException(_i('You must wait up to %d seconds to post again.', $this->radix->getValue('cooldown_new_comment')));
             }
         }
         // we want to know if the comment will display empty, and in case we won't let it pass
         $comment_parsed = $this->processComment();
         if ($this->comment->comment !== '' && $comment_parsed === '') {
             throw new CommentSendingDisplaysEmptyException(_i('This comment would display empty.'));
         }
         // clean up to reset eventual auto-built entries
         $this->comment->clean();
         if ($this->recaptcha_challenge && $this->recaptcha_response && $this->preferences->get('foolframe.auth.recaptcha_public', false)) {
             $recaptcha = ReCaptcha::create($this->preferences->get('foolframe.auth.recaptcha_public'), $this->preferences->get('foolframe.auth.recaptcha_private'));
             $recaptcha_result = $recaptcha->checkAnswer(Inet::dtop($this->comment->poster_ip), $this->recaptcha_challenge, $this->recaptcha_response);
             if (!$recaptcha_result->isValid()) {
                 throw new CommentSendingWrongCaptchaException(_i('Incorrect CAPTCHA solution.'));
             }
         } elseif ($this->preferences->get('foolframe.auth.recaptcha_public')) {
             // if there wasn't a recaptcha input, let's go with heavier checks
             if (substr_count($this->comment->comment, 'http') >= $this->radix->getValue('captcha_comment_link_limit')) {
                 throw new CommentSendingRequestCaptchaException();
             }
             // bots usually fill all the fields
             if ($this->comment->comment && $this->comment->title && $this->comment->email) {
                 throw new CommentSendingRequestCaptchaException();
             }
             // bots usually try various BBC, this checks if there's unparsed BBC after parsing it
             if ($comment_parsed !== '' && substr_count($comment_parsed, '[') + substr_count($comment_parsed, ']') > 4) {
                 throw new CommentSendingRequestCaptchaException();
             }
         }
         // load the spam list and check comment, name, title and email
         $spam = array_filter(preg_split('/\\r\\n|\\r|\\n/', file_get_contents(ASSETSPATH . 'packages/anti-spam/databases/urls.dat')));
         foreach ($spam as $s) {
             if (strpos($this->comment->comment, $s) !== false || strpos($this->comment->name, $s) !== false || strpos($this->comment->title, $s) !== false || strpos($this->comment->email, $s) !== false) {
                 throw new CommentSendingSpamException(_i('Your post has undesidered content.'));
             }
         }
         // check entire length of comment
         if (mb_strlen($this->comment->comment, 'utf-8') > $this->radix->getValue('max_comment_characters_allowed')) {
             throw new CommentSendingTooManyCharactersException(_i('Your comment has too many characters'));
         }
         // check total numbers of lines in comment
         if (count(explode("\n", $this->comment->comment)) > $this->radix->getValue('max_comment_lines_allowed')) {
             throw new CommentSendingTooManyLinesException(_i('Your comment has too many lines.'));
         }
     }
     \Foolz\Plugin\Hook::forge('Foolz\\Foolslide\\Model\\CommentInsert::insert.call.after.input_checks')->setObject($this)->execute();
     // process comment name+trip
     if ($this->comment->name === '') {
         $this->comment->name = $this->radix->getValue('anonymous_default_name');
         $this->comment->trip = null;
     } else {
         $this->processName();
         if ($this->comment->trip === '') {
             $this->comment->trip = null;
         }
     }
     foreach (['email', 'title', 'comment'] as $key) {
         if ($this->comment->{$key} === '') {
             $this->comment->{$key} = null;
         }
     }
     // process comment password
     if ($this->comment->getDelpass() === '') {
         throw new CommentSendingNoDelPassException(_i('You must submit a deletion password.'));
     }
     $pass = password_hash($this->comment->getDelpass(), PASSWORD_BCRYPT, ['cost' => 10]);
     if ($this->comment->getDelpass() === false) {
         throw new \RuntimeException('Password hashing failed');
     }
     $this->comment->setDelpass($pass);
     if ($this->comment->capcode != '') {
         $allowed_capcodes = ['N'];
         if ($this->getAuth()->hasAccess('comment.mod_capcode')) {
             $allowed_capcodes[] = 'M';
         }
         if ($this->getAuth()->hasAccess('comment.admin_capcode')) {
             $allowed_capcodes[] = 'A';
         }
         if ($this->getAuth()->hasAccess('comment.dev_capcode')) {
             $allowed_capcodes[] = 'D';
         }
         if (!in_array($this->comment->capcode, $allowed_capcodes)) {
             throw new CommentSendingUnallowedCapcodeException(_i('You\'re not allowed to use this capcode.'));
         }
     } else {
         $this->comment->capcode = 'N';
     }
     $microtime = str_replace('.', '', (string) microtime(true));
     $this->comment->timestamp = substr($microtime, 0, 10);
     $this->comment->op = (bool) (!$this->comment->thread_num);
     if ($this->radix->getValue('enable_flags')) {
         $reader = new Reader($this->preferences->get('foolframe.maxmind.geoip2_db_path'));
         try {
             $record = $reader->country(Inet::dtop($this->comment->poster_ip));
             $this->comment->poster_country = strtolower($record->country->isoCode);
         } catch (AddressNotFoundException $e) {
             $this->comment->poster_country = 'xx';
         }
     }
     // process comment media
     if ($media !== null) {
         // if uploading an image with OP is prohibited
         if (!$this->comment->thread_num && $this->radix->getValue('op_image_upload_necessity') === 'never') {
             throw new CommentSendingException(_i('You can\'t start a new thread with an image.'));
         }
         if (!$this->allow_media) {
             if ($this->ghost) {
                 throw new CommentSendingImageInGhostException(_i('You can\'t post images when the thread is in ghost mode.'));
             } else {
                 throw new CommentSendingException(_i('This thread has reached its image limit.'));
             }
         }
         try {
             $media->insert($microtime, $this->comment->op);
             $this->media = $media->media;
         } catch (MediaInsertException $e) {
             throw new CommentSendingException($e->getMessage());
         }
     } else {
         // if the user is forced to upload an image when making a new thread
         if (!$this->comment->thread_num && $this->radix->getValue('op_image_upload_necessity') === 'always') {
             throw new CommentSendingThreadWithoutMediaException(_i('You can\'t start a new thread without an image.'));
         }
         // in case of no media, check comment field again for null
         if ($this->comment->comment === null) {
             throw new CommentSendingDisplaysEmptyException(_i('This comment would display empty.'));
         }
         $this->media = $this->bulk->media = new MediaData();
     }
     // 2ch-style codes, only if enabled
     if ($this->comment->thread_num && $this->radix->getValue('enable_poster_hash')) {
         $this->comment->poster_hash = substr(substr(crypt(md5($this->comment->poster_ip . 'id' . $this->comment->thread_num), 'id'), +3), 0, 8);
     }
     $this->comment->timestamp = $this->getRadixTime($this->comment->timestamp);
     \Foolz\Plugin\Hook::forge('Foolz\\Foolslide\\Model\\CommentInsert::insert.call.before.sql')->setObject($this)->execute();
     // being processing insert...
     if ($this->ghost) {
         $num = '
         (
             SELECT MAX(num) AS num
             FROM (
                 (
                     SELECT num
                     FROM ' . $this->radix->getTable() . ' xr
                     WHERE thread_num = ' . $this->dc->getConnection()->quote($this->comment->thread_num) . '
                 )
                 UNION
                 (
                     SELECT num
                     FROM ' . $this->radix->getTable('_deleted') . ' xrd
                     WHERE thread_num = ' . $this->dc->getConnection()->quote($this->comment->thread_num) . '
                 )
             ) x
         )';
         $subnum = '
         (
             SELECT MAX(subnum) + 1 AS subnum
             FROM (
                 (
                     SELECT subnum
                     FROM ' . $this->radix->getTable() . ' xxr
                     WHERE num = (
                         SELECT MAX(num)
                         FROM (
                             (
                                 SELECT num
                                 FROM ' . $this->radix->getTable() . ' xxxr
                                 WHERE thread_num = ' . $this->dc->getConnection()->quote($this->comment->thread_num) . '
                             )
                             UNION
                             (
                                 SELECT num
                                 FROM ' . $this->radix->getTable('_deleted') . ' xxxrd
                                 WHERE thread_num = ' . $this->dc->getConnection()->quote($this->comment->thread_num) . '
                             )
                         ) xxx
                     )
                 )
                 UNION
                 (
                     SELECT subnum
                     FROM ' . $this->radix->getTable('_deleted') . ' xxdr
                     WHERE num = (
                         SELECT MAX(num)
                         FROM (
                             (
                                 SELECT num
                                 FROM ' . $this->radix->getTable() . ' xxxr
                                 WHERE thread_num = ' . $this->dc->getConnection()->quote($this->comment->thread_num) . '
                             )
                             UNION
                             (
                                 SELECT num
                                 FROM ' . $this->radix->getTable('_deleted') . ' xxxdrd
                                 WHERE thread_num = ' . $this->dc->getConnection()->quote($this->comment->thread_num) . '
                             )
                         ) xxxd
                     )
                 )
             ) xx
         )';
         $thread_num = $this->comment->thread_num;
     } else {
         $num = '
         (
             SELECT MAX(num) + 1 AS num
             FROM (
                 (
                     SELECT COALESCE(MAX(num), 0) AS num
                     FROM ' . $this->radix->getTable() . ' xr
                 )
                 UNION
                 (
                     SELECT COALESCE(MAX(num), 0) AS num
                     FROM ' . $this->radix->getTable('_deleted') . ' xdr
                 )
             ) x
         )';
         $subnum = 0;
         if ($this->comment->thread_num > 0) {
             $thread_num = $this->dc->getConnection()->quote($this->comment->thread_num);
         } else {
             $thread_num = '
             (
                 SELECT MAX(thread_num) + 1 AS thread_num
                 FROM (
                     (
                         SELECT COALESCE(MAX(num), 0) as thread_num
                         FROM ' . $this->radix->getTable() . ' xxr
                     )
                     UNION
                     (
                         SELECT COALESCE(MAX(num), 0) as thread_num
                         FROM ' . $this->radix->getTable('_deleted') . ' xxdr
                     )
                 ) xx
             )';
         }
     }
     try {
         $query_fields = ['num' => $num, 'subnum' => $subnum, 'thread_num' => $thread_num];
         $fields = ['media_id' => $this->media->media_id ? $this->media->media_id : 0, 'op' => (int) $this->op, 'timestamp' => $this->comment->timestamp, 'capcode' => $this->comment->capcode, 'email' => $this->comment->email, 'name' => $this->comment->name, 'trip' => $this->comment->trip, 'title' => $this->comment->title, 'comment' => $this->comment->comment, 'delpass' => $this->comment->getDelpass(), 'spoiler' => (int) $this->media->spoiler, 'poster_ip' => $this->comment->poster_ip, 'poster_hash' => $this->comment->poster_hash, 'poster_country' => $this->comment->poster_country, 'preview_orig' => $this->media->preview_orig, 'preview_w' => $this->media->preview_w, 'preview_h' => $this->media->preview_h, 'media_filename' => $this->media->media_filename, 'media_w' => $this->media->media_w, 'media_h' => $this->media->media_h, 'media_size' => $this->media->media_size, 'media_hash' => $this->media->media_hash, 'media_orig' => $this->media->media_orig, 'exif' => $this->media->exif !== null ? @json_encode($this->media->exif) : null, 'timestamp_expired' => 0];
         foreach ($fields as $key => $item) {
             if ($item === null) {
                 $fields[$key] = 'null';
             } else {
                 $fields[$key] = $this->dc->getConnection()->quote($item);
             }
         }
         $fields = $query_fields + $fields;
         $this->dc->getConnection()->beginTransaction();
         $this->dc->getConnection()->executeUpdate('INSERT INTO ' . $this->radix->getTable() . ' (' . implode(', ', array_keys($fields)) . ') VALUES (' . implode(', ', array_values($fields)) . ')');
         $last_id = $this->dc->getConnection()->lastInsertId($this->radix->getTable('_doc_id_seq'));
         $comment = $this->dc->qb()->select('*')->from($this->radix->getTable(), 'r')->where('doc_id = :doc_id')->setParameter(':doc_id', $last_id)->execute()->fetchAll();
         $this->bulk->import($comment[0], $this->radix);
         if (!$this->radix->archive) {
             $this->insertTriggerThreads();
             $this->insertTriggerDaily();
             $this->insertTriggerUsers();
         }
         // update poster_hash for op posts
         if ($this->comment->op && $this->radix->getValue('enable_poster_hash')) {
             $this->comment->poster_hash = substr(substr(crypt(md5($this->comment->poster_ip . 'id' . $this->comment->thread_num), 'id'), 3), 0, 8);
             $this->dc->qb()->update($this->radix->getTable(), 'ph')->set('poster_hash', $this->dc->getConnection()->quote($this->comment->poster_hash))->where('doc_id = :doc_id')->setParameter(':doc_id', $this->comment->doc_id)->execute();
         }
         $this->dc->getConnection()->commit();
         // clean up some caches
         Cache::item('foolslide.model.board.getThreadComments.thread.' . md5(serialize([$this->radix->shortname, $this->comment->thread_num])))->delete();
         // clean up the 10 first pages of index and gallery that are cached
         for ($i = 1; $i <= 10; $i++) {
             Cache::item('foolslide.model.board.getLatestComments.query.' . $this->radix->shortname . '.by_post.' . $i)->delete();
             Cache::item('foolslide.model.board.getLatestComments.query.' . $this->radix->shortname . '.by_thread.' . $i)->delete();
             Cache::item('foolslide.model.board.getThreadsComments.query.' . $this->radix->shortname . '.' . $i)->delete();
         }
     } catch (\Doctrine\DBAL\DBALException $e) {
         $this->logger->error('\\Foolz\\Foolslide\\Model\\CommentInsert: ' . $e->getMessage());
         $this->dc->getConnection()->rollBack();
         throw new CommentSendingDatabaseException(_i('Something went wrong when inserting the post in the database. Try again.'));
     }
     return $this;
 }
Example #7
0
 public function setBulk(CommentBulk $bulk)
 {
     $this->radix = $bulk->getRadix();
     $this->bulk = $bulk;
     $this->media = $bulk->media;
     // some cases we don't have a comment attached, like banning/deleting
     if (isset($bulk->comment)) {
         $this->op = $bulk->comment->op;
     }
     if ($this->radix->archive) {
         // archive entries for media_filename are already encoded and we risk overencoding
         $this->media->media_filename = html_entity_decode($this->media->media_filename, ENT_QUOTES, 'UTF-8');
     }
     // let's unset 0 sizes so maybe the __get() can save the day
     if (!$this->media->preview_w || !$this->media->preview_h) {
         $this->media->preview_h = 0;
         $this->media->preview_w = 0;
         if ($this->radix->archive && $this->media->spoiler) {
             try {
                 $imgsize = Cache::item('foolfuuka.media.call.spoiler_size.' . $this->radix->id . '.' . $this->media->media_id . '.' . ($this->op ? 'op' : 'reply'))->get();
                 $this->media->preview_w = $imgsize[0];
                 $this->media->preview_h = $imgsize[1];
             } catch (\OutOfBoundsException $e) {
                 $imgpath = $this->getDir(true);
                 if ($imgpath !== null) {
                     $imgsize = @getimagesize($imgpath);
                     Cache::item('foolfuuka.media.call.spoiler_size.' . $this->radix->id . '.' . $this->media->media_id . '.' . ($this->op ? 'op' : 'reply'))->set($imgsize, 86400);
                     if ($imgsize !== false) {
                         $this->media->preview_w = $imgsize[0];
                         $this->media->preview_h = $imgsize[1];
                     }
                 }
             }
         }
     }
     // we set them even for admins
     if ($this->media->banned) {
         $this->media->media_status = static::STATUS_BANNED;
     } elseif ($this->radix->hide_thumbnails && !$this->getAuth()->hasAccess('media.see_hidden')) {
         $this->media->media_status = static::STATUS_FORBIDDEN;
     } else {
         $this->media->media_status = static::STATUS_NORMAL;
     }
 }
Example #8
0
 /**
  * Puts the table in readily available variables
  */
 public function preload()
 {
     $this->profiler->log('Radix::preload Start');
     try {
         $result = Cache::item('foolfuuka.model.radix.preload')->get();
     } catch (\OutOfBoundsException $e) {
         $result = $this->dc->qb()->select('*')->from($this->dc->p('boards'), 'b')->orderBy('shortname', 'ASC')->execute()->fetchAll();
         Cache::item('foolfuuka.model.radix.preload')->set($result, 900);
     }
     if (!is_array($result) || empty($result)) {
         $this->preloaded_radixes = [];
         return false;
     }
     $result_object = [];
     foreach ($result as $item) {
         // don't process hidden boards
         if (!$this->getAuth()->hasAccess('boards.see_hidden') && $item['hidden'] == 1) {
             continue;
         }
         $structure = $this->structure($item);
         $result_object[$item['id']] = new Radix($this->getContext(), $this);
         // set the plain database data as keys
         foreach ($item as $k => $i) {
             $result_object[$item['id']]->{$k} = $i;
             // we set it also in the values so we can just use it from there as commodity
             $result_object[$item['id']]->setValue($k, $i);
         }
         // url values for commodity
         $result_object[$item['id']]->setValue('formatted_title', $item['name'] ? '/' . $item['shortname'] . '/ - ' . $item['name'] : '/' . $item['shortname'] . '/');
         // load the basic value of the preferences
         foreach ($structure as $key => $arr) {
             if (!isset($result_object[$item['id']]->{$key}) && isset($arr['boards_preferences'])) {
                 $result_object[$item['id']]->setValue($key, $this->config->get('foolz/foolfuuka', 'package', 'preferences.radix.' . $key, false));
             }
             foreach (['sub', 'sub_inverse'] as $sub) {
                 if (isset($arr[$sub])) {
                     foreach ($arr[$sub] as $k => $a) {
                         if (!isset($result_object[$item['id']]->{$k}) && isset($a['boards_preferences'])) {
                             $result_object[$item['id']]->setValue($k, $this->config->get('foolz/foolfuuka', 'package', 'preferences.radix.' . $k, false));
                         }
                     }
                 }
             }
         }
     }
     // load the preferences from the board_preferences table
     $this->profiler->log('Radix::load_preferences Start');
     try {
         $preferences = Cache::item('foolfuuka.model.radix.load_preferences')->get();
     } catch (\OutOfBoundsException $e) {
         $preferences = $this->dc->qb()->select('*')->from($this->dc->p('boards_preferences'), 'p')->execute()->fetchAll();
         Cache::item('foolfuuka.model.radix.load_preferences')->set($preferences, 900);
     }
     foreach ($preferences as $value) {
         // in case of leftover values, it would try instantiating a new stdClass and that would trigger error
         if (isset($result_object[$value['board_id']])) {
             $result_object[$value['board_id']]->setValue($value['name'], $value['value']);
         }
     }
     $this->preloaded_radixes = $result_object;
     $this->profiler->logMem('Radix $this->preloaded_radixes', $this->preloaded_radixes);
     $this->profiler->log('Radix::load_preferences End');
     // take them all and then filter/do whatever (we use this to split the boards through various subdomains)
     // only public is affected! admins and mods will see all boards at all the time
     $this->preloaded_radixes = \Foolz\Plugin\Hook::forge('Foolz\\Foolfuuka\\Model\\Radix::preload.result.public')->setObject($this)->setParam('preloaded_radixes', $this->preloaded_radixes)->execute()->get($this->preloaded_radixes);
     $this->profiler->log('Radix::preload End');
     $this->profiler->logMem('Radix $this->preloaded_radixes w/ preferences', $this->preloaded_radixes);
 }
Example #9
0
 /**
  * Delete the post and eventually the entire thread if it's OP
  * Also deletes the images when it's the only post with that image
  *
  * @param null $password
  * @param bool $force
  * @param bool $thread
  * @throws CommentSendingDatabaseException
  * @throws CommentDeleteWrongPassException
  * @return array|bool
  */
 protected function p_delete($password = null, $force = false, $thread = false)
 {
     if (!$this->getAuth()->hasAccess('comment.passwordless_deletion') && $force !== true) {
         if (!password_verify($password, $this->comment->getDelpass())) {
             throw new CommentDeleteWrongPassException(_i('You did not provide the correct deletion password.'));
         }
     }
     try {
         $this->dc->getConnection()->beginTransaction();
         // check that the post isn't already in deleted
         $has_deleted = $this->dc->qb()->select('COUNT(*) as found')->from($this->radix->getTable('_deleted'), 'd')->where('doc_id = :doc_id')->setParameter(':doc_id', $this->comment->doc_id)->execute()->fetch();
         if (!$has_deleted['found']) {
             // throw into _deleted table
             $this->dc->getConnection()->executeUpdate('INSERT INTO ' . $this->radix->getTable('_deleted') . ' ' . $this->dc->qb()->select('*')->from($this->radix->getTable(), 't')->where('doc_id = ' . $this->dc->getConnection()->quote($this->comment->doc_id))->getSQL());
         }
         // delete post
         $this->dc->qb()->delete($this->radix->getTable())->where('doc_id = :doc_id')->setParameter(':doc_id', $this->comment->doc_id)->execute();
         // purge reports
         $this->dc->qb()->delete($this->dc->p('reports'))->where('board_id = :board_id')->andWhere('doc_id = :doc_id')->setParameter(':board_id', $this->radix->id)->setParameter(':doc_id', $this->comment->doc_id)->execute();
         // clear cache
         $this->radix_coll->clearCache();
         // remove image file
         if (isset($this->media)) {
             $media_sql = $this->dc->qb()->select('COUNT(*)')->from($this->radix->getTable(), 't')->where('media_id = :media_id')->setParameter(':media_id', $this->media->media_id)->getSQL();
             $this->dc->qb()->update($this->radix->getTable('_images'))->set('total', '(' . $media_sql . ')')->where('media_id = :media_id')->setParameter(':media_id', $this->media->media_id)->execute();
             $has_image = $this->dc->qb()->select('total')->from($this->radix->getTable('_images'), 'ti')->where('media_id = :media_id')->setParameter(':media_id', $this->media->media_id)->execute()->fetch();
             if (!$has_image || !$has_image['total']) {
                 $media = new Media($this->getContext(), $this->bulk);
                 $media->delete();
             }
         }
         // if this is OP, delete replies too
         if ($this->comment->op) {
             // delete thread data
             $this->dc->qb()->delete($this->radix->getTable('_threads'))->where('thread_num = :thread_num')->setParameter(':thread_num', $this->comment->thread_num)->execute();
             // process each comment
             $comments = $this->dc->qb()->select('doc_id')->from($this->radix->getTable(), 'b')->where('thread_num = :thread_num')->setParameter(':thread_num', $this->comment->thread_num)->execute()->fetchAll();
             foreach ($comments as $comment) {
                 $post = Board::forge($this->getContext())->getPost()->setOptions('doc_id', $comment['doc_id'])->setRadix($this->radix)->getComments();
                 $post = current($post);
                 $post = new Comment($this->getContext(), $post);
                 $post->delete(null, true, true);
             }
         } else {
             // if this is not triggered by a thread deletion, update the thread table
             if ($thread === false && !$this->radix->archive) {
                 $time_last = '
                 (
                     COALESCE(GREATEST(
                         time_op,
                         (
                             SELECT MAX(timestamp) FROM ' . $this->radix->getTable() . ' xr
                             WHERE thread_num = ' . $this->dc->getConnection()->quote($this->comment->thread_num) . ' AND subnum = 0
                         )
                     ), time_op)
                 )';
                 $time_bump = '
                 (
                     COALESCE(GREATEST(
                         time_op,
                         (
                             SELECT MAX(timestamp) FROM ' . $this->radix->getTable() . ' xr
                             WHERE thread_num = ' . $this->dc->getConnection()->quote($this->comment->thread_num) . ' AND subnum = 0
                                 AND (email <> \'sage\' OR email IS NULL)
                         )
                     ), time_op)
                 )';
                 $time_ghost = '
                 (
                     SELECT MAX(timestamp) FROM ' . $this->radix->getTable() . ' xr
                     WHERE thread_num = ' . $this->dc->getConnection()->quote($this->comment->thread_num) . ' AND subnum <> 0
                 )';
                 $time_ghost_bump = '
                 (
                     SELECT MAX(timestamp) FROM ' . $this->radix->getTable() . ' xr
                     WHERE thread_num = ' . $this->dc->getConnection()->quote($this->comment->thread_num) . ' AND subnum <> 0
                         AND (email <> \'sage\' OR email IS NULL)
                 )';
                 // update thread information
                 $this->dc->qb()->update($this->radix->getTable('_threads'))->set('time_last', $time_last)->set('time_bump', $time_bump)->set('time_ghost', $time_ghost)->set('time_ghost_bump', $time_ghost_bump)->set('time_last_modified', ':time')->set('nreplies', 'nreplies - 1')->set('nimages', $this->media === null ? 'nimages' : 'nimages - 1')->where('thread_num = :thread_num')->setParameter(':time', $this->getRadixTime())->setParameter(':thread_num', $this->comment->thread_num)->execute();
             }
         }
         $this->dc->getConnection()->commit();
         // clean up some caches
         Cache::item('foolfuuka.model.board.getThreadComments.thread.' . md5(serialize([$this->radix->shortname, $this->comment->thread_num])))->delete();
         // clean up the 10 first pages of index and gallery that are cached
         for ($i = 1; $i <= 10; $i++) {
             Cache::item('foolfuuka.model.board.getLatestComments.query.' . $this->radix->shortname . '.by_post.' . $i)->delete();
             Cache::item('foolfuuka.model.board.getLatestComments.query.' . $this->radix->shortname . '.by_thread.' . $i)->delete();
             Cache::item('foolfuuka.model.board.getThreadsComments.query.' . $this->radix->shortname . '.' . $i)->delete();
         }
     } catch (\Doctrine\DBAL\DBALException $e) {
         $this->logger->error('\\Foolz\\Foolfuuka\\Model\\CommentInsert: ' . $e->getMessage());
         $this->dc->getConnection()->rollBack();
         throw new CommentSendingDatabaseException(_i('Something went wrong when deleting the post in the database. Try again.'));
     }
     return $this;
 }
Example #10
0
 /**
  * Clears the cached objects for the entire class
  */
 public function p_clearCache()
 {
     $this->preloaded = null;
     Cache::item('foolfuuka.model.report.preload.preloaded')->delete();
 }
Example #11
0
 /**
  * Called directly from index.php
  * Starts up the Symfony components and the FoolFrame components
  */
 public function __construct()
 {
     $this->container = new ContainerBuilder();
     $this->container->register('profiler', 'Foolz\\Profiler\\Profiler')->addMethodCall('enable', []);
     $this->profiler = $this->container->get('profiler');
     class_alias('Foolz\\FoolFrame\\Model\\Plugins', 'Plugins');
     class_alias('Foolz\\FoolFrame\\Model\\SchemaManager', 'SchemaManager');
     class_alias('Foolz\\FoolFrame\\Model\\System', 'System');
     class_alias('Foolz\\FoolFrame\\Model\\User', 'User');
     class_alias('Foolz\\FoolFrame\\Model\\Users', 'Users');
     $this->route_collection = new RouteCollection();
     $this->logger = new MonoLogger('foolframe');
     $this->logger->pushHandler(new RotatingFileHandler(VAPPPATH . 'foolz/foolframe/logs/foolframe.log', 7, MonoLogger::WARNING));
     $this->logger->pushProcessor(new IntrospectionProcessor());
     $this->logger->pushProcessor(new WebProcessor());
     // special logger that saves stack traces from the exception handler
     $this->logger_trace = new MonoLogger('foolframe_trace');
     $this->logger_trace->pushHandler(new RotatingFileHandler(VAPPPATH . 'foolz/foolframe/logs/foolframe_trace.log', 7, MonoLogger::WARNING));
     $this->logger_trace->pushProcessor(new IntrospectionProcessor());
     $this->logger_trace->pushProcessor(new WebProcessor());
     if ('cli' !== php_sapi_name()) {
         error_reporting(-1);
         $this->error_handler = ErrorHandler::register();
         $this->error_handler->setLogger($this->logger_trace);
         $this->exception_handler = ExceptionHandler::register(false);
         $this->exception_handler->setLogger($this->logger);
         $this->exception_handler->setLoggerTrace($this->logger_trace);
     } elseif (!ini_get('log_errors') || ini_get('error_log')) {
         ini_set('display_errors', 1);
     }
     $this->container->register('autoloader', 'Foolz\\FoolFrame\\Model\\Autoloader')->addArgument($this)->addMethodCall('register');
     $this->container->register('logger', 'Foolz\\FoolFrame\\Model\\Logger')->addArgument($this)->addMethodCall('addLogger', [$this->logger])->addMethodCall('addLogger', [$this->logger_trace]);
     $this->container->register('config', 'Foolz\\FoolFrame\\Model\\Config')->addArgument($this);
     $this->container->register('doctrine', 'Foolz\\FoolFrame\\Model\\DoctrineConnection')->addArgument($this)->addArgument(new Reference('config'));
     $this->container->register('mailer', 'Foolz\\FoolFrame\\Model\\Mailer')->addArgument($this);
     $this->container->register('preferences', 'Foolz\\FoolFrame\\Model\\Preferences')->addArgument($this);
     $this->container->register('plugins', 'Foolz\\FoolFrame\\Model\\Plugins')->addArgument($this);
     $this->container->register('users', 'Foolz\\FoolFrame\\Model\\Users')->addArgument($this);
     $this->container->register('auth', 'Foolz\\FoolFrame\\Model\\Auth')->addArgument($this);
     $this->container->register('security', 'Foolz\\FoolFrame\\Model\\Security')->addArgument($this);
     $this->config = $this->getService('config');
     $this->preferences = $this->getService('preferences');
     // start up the caching system
     $caching_config = $this->config->get('foolz/foolframe', 'cache', '');
     switch ($caching_config['type']) {
         case 'redis':
             $mem_config = \Foolz\Cache\Config::forgeRedis();
             $mem_config->setFormat($caching_config['format']);
             $mem_config->setPrefix($caching_config['prefix']);
             $mem_config->setServers($caching_config['servers']);
             $mem_config->setThrow(true);
             Cache::instantiate($mem_config);
             break;
         case 'memcached':
             $mem_config = \Foolz\Cache\Config::forgeMemcached();
             $mem_config->setFormat($caching_config['format']);
             $mem_config->setPrefix($caching_config['prefix']);
             $mem_config->setServers($caching_config['servers']);
             $mem_config->setThrow(true);
             Cache::instantiate($mem_config);
             break;
         case 'apc':
             $apc_config = \Foolz\Cache\Config::forgeApc();
             $apc_config->setFormat($caching_config['format']);
             $apc_config->setPrefix($caching_config['prefix']);
             $apc_config->setThrow(true);
             Cache::instantiate($apc_config);
             break;
         case 'dummy':
             $dummy_config = \Foolz\Cache\Config::forgeDummy();
             $dummy_config->setFormat($caching_config['format']);
             $dummy_config->setPrefix($caching_config['prefix']);
             $dummy_config->setThrow(true);
             Cache::instantiate($dummy_config);
             break;
     }
     // run the Framework class for each module
     foreach ($this->config->get('foolz/foolframe', 'config', 'modules.installed') as $module) {
         if ($module['namespace'] !== 'foolz/foolframe') {
             $context = $module['context'];
             $this->child_contextes[$module['namespace']] = new $context($this);
         }
     }
     $this->profiler->log('Start Plugin instantiation');
     if (count($this->child_contextes)) {
         $this->getService('plugins')->instantiate();
     }
     $this->profiler->log('Stop Plugin instantiation');
 }