Welcome¶
Introduction¶
FoolFuuka was designed to accomplish two different goals: (1) function as an image-based bulletin board software, and (2) provide a functional front-end interface for Asagi. In order to accomplish the latter, you’ll need to prepare and configure your server environment properly.
Features¶
Requirements¶
Web Server¶
You’ll need to install one of the following web servers to allow users to access the web interface:
- Apache
- nginx (Recommended)
See also
Database¶
FoolFuuka supports the following database servers:
- MariaDB 5.5+ (Recommended)
- MySQL 5.5+
Note
When dealing with large amounts of data, we recommend using the TokuDB storage engine for all board tables which is available with MariaDB. This mainly applies to deployments used to provide a front-end for Asagi and archives.
Git/Composer¶
FoolFuuka utilizes both Git and Composer to manage all of its dependencies, software updates, and web assets.
PHP/HHVM¶
While FoolFuuka is designed to work on PHP 5.4 or newer, it is also compatible with HHVM.
Search Server¶
FoolFuuka requires an additional software to index and serve search results to users. This is achieved with Sphinx Open Source Search Server which must be installed to provide users with search capabilities.
Note
FoolFuuka includes a Sphinx configuration file generator in the web administration interface and should be used to generate a new sphinx configuration file accordingly.
ImageMagick¶
If you plan to use FoolFuuka as an image-based bulletin board, ImageMagick must be installed on the server. The binary files are used to generate and manipulate image files.
Note
You may be required to specify the path for ImageMagick’s convert binary in the administrative panel.
Installation¶
Install¶
Via Composer¶
$ composer create-project foolz/foolfuuka foolfuuka --prefer-source
$ cd foolfuuka
$ composer dump-autoload --optimize
Warning
When asked to remove the VCS files (.git), you must choose N so that the version control system remains intact. This will allow you to perform future upgrades.
Via Source Code¶
$ git clone https://github.com/FoolCode/FoolFuuka foolfuuka
$ cd foolfuuka
$ git checkout 2-2-stable
$ composer install --optimize-autoloader
Upgrading¶
$ git fetch --all
$ git checkout 2-2-stable
$ composer update --optimize
Note
The commands provided above will only upgrade the FoolFuuka code. You may be required to complete some additional steps to completely upgrade FoolFuuka to the next version. Please consult the upgrade guides to ensure that the upgrade process is done properly.
See also
Configuration¶
While most of the configurable settings are exposed through the web administrative panel, there are still a number of settings that can only be modified manually due to security concerns.
Note
In this documentation, we will use dot notations to specify the location of the config key being listed.
FoolFrame¶
These config files are used to manage many of the core settings in the FoolFuuka framework. You can locate these files in the following path after installation: vendor/foolz/foolframe/config/.
Note
We recommend that you copy these config files into and edit them in the following directory: app/foolz/foolframe/config/. The software is designed to load these files instead of the default config files.
cache¶
- type
Type: STRING Default: dummy
- format
Type: STRING Default: smart_json
- prefix
Type: STRING Default: empty
- servers
Type: ARRAY Default: empty
config¶
- config.cookie_prefix
Type: STRING Default: empty
- install.installed
Type: BOOLEAN Default: false
- modules.installed
Type: ARRAY
db¶
- active
Type: STRING Default: default
- default.driver
Type: STRING Default: pdo_mysql
- default.host
Type: STRING Default: localhost
- default.port
Type: INT Default: 3306
- default.dbname
Type: STRING Default: empty
- default.user
Type: STRING Default: empty
- default.password
Type: STRING Default: empty
- default.persistent
Type: BOOLEAN Default: false
- default.prefix
Type: STRING Default: empty
- default.charset
Type: STRING Default: utf8mb4
foolauth¶
- db_connection
Type: STRING Default: null
- table_name
Type: STRING Default: users
- table_autologin_name
Type: STRING Default: user_autologin
- table_login_attempts_name
Type: STRING Default: user_login_attempts
- table_columns
Type: ARRAY
- guest_login
Type: BOOLEAN Default: true
- groups
Type: ARRAY
- roles
Type: ARRAY
- login_hash_salt
Type: STRING Default: empty
- salt
Type: STRING Default: empty
- username_post_key
Type: STRING Default: username
- password_post_key
Type: STRING Default: password
- attempts_to_lock
Type: INT Default: 10
FoolFuuka¶
These config files are used to manage many of the core settings in FoolFuuka that we considered very important and shouldn’t be exposed in the web interface. You can locate these files in the following path after installation: assets/config/.
Note
We recommend that you copy these config files into and edit them in the following directory: app/foolz/foolfuuka/config/. The software is designed to load these files instead of the default config files.
config¶
- comment.secure_tripcode_salt
Type: STRING Default: null This is the salt used to for secure tripcodes. It is recommend that this salt key be changed when exposed or kept consistent between installations.
- media.filecheck
Type: BOOLEAN Default: true Checks if the media file exists on the disk. The setting does impact disk performance when enabled due to lstat calls for each file being checked.
Value Effect true enables the check and returns a generated link based on file existence false disables the check and returns a full link
foolauth¶
- roles
Type: ARRAY
CHANGELOG¶
What’s New in FoolFuuka 2.2.0¶
FoolFuuka 2.2.0 includes a few new features and an overhaul in parts of the code base. The most notable change is the removal of all plugins from the standard distribution which will need to be re-installed manually.
Features¶
- added GroupByThread option for search results
- added highlight.js for code highlighting
- added configurable swiftmailer config file for Mailer
Performance¶
- changed autoloading of themes and various components to PSR-4
- removed entire media.filecheck logic
Fixes¶
- removed trailing forward-slash in default media url
- reports view now displays board name and view button
- rewrote sticky/locked toggle logic on archive boards
Misc.¶
- added additional software hooks in Comment
- decoupled all plugins from standard distribution
- moved 4chan specific BBCode to separate plugin
- replaced StringParser with jBBCode
- updated FoolFuuka namespace
- updated FoolFuuka dependencies
User Guide¶
Asagi¶
Compiling Asagi¶
$ git clone https://github.com/FoolCode/asagi.git
$ mvn package assembly:single
Configuring Asagi¶
Asagi uses a JSON configuration file named asagi.json. An example configuration file is included within thegit repository as asagi.json.example.
Warning
If you are using MySQL/MariaDB as your database server, you must set the character_set_server setting under the [mysqld] section to utf8mb4 in your my.cnf file. This will allow you to properly store multi-byte unicode characters properly.
Running Asagi¶
$ java -Xmx256m -XX:+UseParNewGC -XX:MaxPermSize=24m -jar asagi.jar
Note
We strongly recommend the usage of screen or tmux with Asagi. Also, you may be required to adjust the Xmx and XX:MaxPermSize values accordingly.
Configuring FoolFuuka¶
Warning
It is very crucial that you configure and run/restart Asagi before adding the board to FoolFuuka. This will allow Asagi to create the board tables properly with some additional steps that aren’t included in FoolFuuka. If this is not done, the board tables will not be populated properly.
You must first configure FoolFuuka to use the Asagi database created in the previous steps. This can be done by following the steps listed below:
- Access the FoolFuuka Administrative Panel
- Navigate to Preferences under the Boards section
- Set the Boards Database field to the same database name used in the asagi.json config file
- Save your changes
Note
The steps listed above only need to be completed once.
In order to access the boards being archived with Asagi, you will need to add the boards to FoolFuuka by following the steps listed below:
- Access the FoolFuuka Administrative Panel
- Navigate to Manage under the Boards section
- Click “Add Board”
- Fill out the required fields properly
- Check the “Is this an archived board?” checkbox
- Click “Submit” to add the board to the database
Note
You will need to repeat the steps listed above each time you wish to add a board archived by Asagi.
Upgrade Guide¶
From 2.0 to 2.1¶
As of 2.1.0, we’ve deprecated the original FoolFuuka installer repository and changed the folder structure of the FoolFuuka installations.
Backup¶
You will need to create a backup of the following folders or move them to a new location:
- app/
- public/foolfuuka/boards/
Note
Depending upon your configuration, you may not need to backup the public/foolfuuka/boards/ directory.
Obtain the Latest Code¶
You can install the latest stable version of 2.1 by using one of the following methods:
Via Composer¶
$ composer create-project foolz/foolfuuka foolfuuka
$ cd foolfuuka
$ composer dump-autoload --optimize
Via Source Code¶
$ git clone https://github.com/FoolCode/FoolFuuka foolfuuka
$ cd foolfuuka
$ git checkout 2-1-stable
$ composer install --optimize
Copy App Files and Data¶
You will need to restore the following folders from the backup to the same locations:
- app/
- public/foolfuuka/boards/
Note
Depending upon your configuration, you may not need to restore the public/foolfuuka/boards/ directory.
From 2.1 to 2.2¶
Backup¶
We recommend that you create a backup of the following folders or move them to a safe location:
- app/
- public/foolfuuka/boards/
Note
Depending upon your configuration, you may not need to backup the public/foolfuuka/boards/ directory.
Obtain the Latest Code¶
$ cd /path/to/foolfuuka
$ git checkout 2-2-stable
$ composer update --optimize
Update Core Framework Config Files¶
You are required to update the app/foolz/foolframe/config/config.php file to match the following config provided:
<?php
return array(
'config' => array(
'cookie_prefix' => 'foolframe_NEW_',
),
'install' => array(
'installed' => true,
),
'modules' => array(
'installed' => array(
'foolframe' => array(
'context' => '\\Foolz\\FoolFrame\\Model\\Context',
'namespace' => 'foolz/foolframe',
),
'foolfuuka' => array(
'context' => '\\Foolz\\FoolFuuka\\Model\\Context',
'namespace' => 'foolz/foolfuuka',
),
),
),
);
Developer Guide¶
Code Documentation¶
REST API¶
Index¶
GET /_/api/chan/index/
Property | Type | Description | Required |
---|---|---|---|
board | string | This is the shortname for the board. | Y |
page | integer | The page number of the index. | Y |
{
"2": {
"omitted": 10,
"images_omitted": 10,
"op": {
"<POST OBJECT>"
},
"posts": [
{
"<POST OBJECT>"
}
]
},
"1": {
"omitted": 10,
"images_omitted": 10,
"op": {
"<POST OBJECT>"
},
"posts": [
{
"<POST OBJECT>"
}
]
}
}
Search¶
GET /_/api/chan/search/
Property | Type | Description | Required |
---|---|---|---|
board | mixed | This is the shortname for the board. | Y |
string | N | ||
username | string | N | |
tripcode | string | N | |
capcode | string | N | |
subject | string | N | |
text | string | N | |
filename | string | N | |
filehash | string | N | |
deleted | integer | N | |
ghost | integer | N | |
filter | integer | N | |
date_start | string | N | |
date_end | string | N | |
order | string | N |
[
{
"posts": [
{
"<POST OBJECT>"
},
{
"<POST OBJECT>"
}
]
}
]
Thread¶
GET /_/api/chan/thread/?board=dev&num=1
Property | Type | Description | Required |
---|---|---|---|
board | string | This is the shortname for the board. | Y |
num | integer | This is the post number of the thread. | Y |
latest_doc_id | integer | This is the latest doc_id used as a starting point. | N |
last_limit | integer | This limits the results to the last x posts. | N |
{
"1": {
"op": {
"<POST OBJECT>"
},
"posts": {
"2": {
"<POST OBJECT>"
},
"3": {
"<POST OBJECT>"
}
}
}
}
Post¶
GET /_/api/chan/post/?board=dev&num=1
Property | Type | Description | Required |
---|---|---|---|
board | string | This is the shortname for the board. | Y |
num | mixed | This is the post number. | Y |
{
"doc_id": "1",
"poster_ip": "1111111111",
"num": "1",
"subnum": "0",
"thread_num": "1",
"op": "1",
"timestamp": "1339024666",
"timestamp_expired": "0",
"capcode": "A",
"email": null,
"name": "Anonymous",
"trip": null,
"title": null,
"comment": "COMMENT DATA HERE",
"poster_hash": "fUSBgQ2y",
"poster_country": null,
"deleted": "0",
"sticky": "0",
"comment_processed": "COMMENT DATA HERE",
"title_processed": "",
"name_processed": "Anonymous",
"email_processed": "",
"trip_processed": "",
"poster_hash_processed": "fUSBgQ2y",
"fourchan_date": "6\/6\/12(Wed)23:17",
"comment_sanitized": "COMMENT DATA HERE",
"poster_country_name_processed": null,
"media": {
"op": "1",
"media_id": "1024",
"spoiler": "0",
"preview_orig": "13390246665411s.jpg",
"preview_w": "216",
"preview_h": "250",
"media_filename": "8211205.jpg",
"media_w": "742",
"media_h": "860",
"media_size": "130990",
"media_hash": "P2asAleYuUWVvEFBotaaxA==",
"media_orig": "13390246665411.jpg",
"exif": null,
"total": "1",
"banned": "0",
"media": "13390246665411.jpg",
"preview_op": "13390246665411s.jpg",
"preview_reply": null,
"media_status": "normal",
"safe_media_hash": "P2asAleYuUWVvEFBotaaxA",
"preview_orig_processed": "13390246665411s.jpg",
"media_filename_processed": "8211205.jpg",
"media_hash_processed": "P2asAleYuUWVvEFBotaaxA==",
"media_link": "https:\/\/0-media-cdn.foolz.us\/ffuuka\/board\/dev\/image\/1339\/02\/13390246665411.jpg",
"remote_media_link": "https:\/\/0-media-cdn.foolz.us\/ffuuka\/board\/dev\/image\/1339\/02\/13390246665411.jpg",
"thumb_link": "https:\/\/0-media-cdn.foolz.us\/ffuuka\/board\/dev\/thumb\/1339\/02\/13390246665411s.jpg"
}
}
Software Hooks¶
Plugin¶
Foolz\Plugin\Plugin::execute#<plugin-name>¶
->setObject($plugin)
->setParam('context', $this->getContext())
Foolz\FoolFrame\Model\Plugin::install#<plugin-name>¶
->setParam('context', $this->getContext())
->setParam('schema', $sm->getCodedSchema())
FoolFrame¶
Foolz\FoolFrame\Controller\Admin::before#var.sidebar¶
->setObject($this)
->setParam('sidebar', [])
Foolz\FoolFrame\Model\Context::handleConsole#obj.app¶
->setObject($this)
->setParam('application', $application)
Foolz\FoolFrame\Model\Context::handleWeb#obj.afterAuth¶
->setObject($this)
->setParam('route_collection', $this->route_collection)
Foolz\FoolFrame\Model\Context::handleWeb#obj.routing¶
->setObject($this)
->setParam('route_collection', $this->route_collection)
Foolz\FoolFrame\Model\Context::handleWeb#obj.context¶
->setObject($this)
Foolz\FoolFrame\Model\Context::handleWeb#obj.request¶
->setObject($this)
->setParam('request', $request)
Foolz\FoolFrame\Model\Context::handleWeb#obj.response¶
->setObject($this)
->setParam('request', $request)
Foolz\FoolFrame\Model\Preferences::load#var.preferences¶
->setObject($this)
->setParam('preferences', $this->preferences)
Foolz\FoolFrame\Model\SchemaManager::forge#var.ignorePrefix¶
->setObject(new static())
->setParam('prefixes', $prefixes)
Foolz\FoolFrame\Model\SchemaManager::forge#var.tables¶
->setObject(new static())
->setParam('tables', $tables)
Foolz\FoolFrame\Model\System::getEnvironment#var.environment¶
->setParam('environment', $environment)
FoolFuuka¶
Foolz\FoolFuuka\Model\Comment::processComment#var.greentext¶
->setParam('html', $html)
Foolz\FoolFuuka\Model\Comment::processComment#var.originalComment¶
->setObject($this)
->setParam('comment', $this->comment->comment)
Foolz\FoolFuuka\Model\Comment::processComment#var.processedComment¶
->setObject($this)
->setParam('comment', $this->comment->comment)
Foolz\FoolFuuka\Model\Comment::processCommentBBCode#var.definitions¶
->setObject($this)
->setParam('definitions', $definitions)
Foolz\FoolFuuka\Model\Comment::processExternalLinks#var.link¶
->setObject($this)
->setParam('data', $data)
->setParam('build_href', $build_href)
Foolz\FoolFuuka\Model\Comment::processInternalLinks#var.link¶
->setObject($this)
->setParam('data', $data)
->setParam('build_url', $build_url)
Foolz\FoolFuuka\Model\CommentInsert::insert#obj.captcha¶
->setObject($this)
Foolz\FoolFuuka\Model\CommentInsert::insert#obj.afterInputCheck¶
->setObject($this)
Foolz\FoolFuuka\Model\CommentInsert::insert#obj.comment¶
->setObject($this)
Foolz\FoolFuuka\Model\Context::loadRoutes#obj.beforeRouting¶
->setObject($this)
->setParam('route_collection', $route_collection)
Foolz\FoolFuuka\Model\Context::loadRoutes#var.collection¶
->setParam('default_suffix', page)
->setParam('suffix', page)
->setParam('controller', 'Foolz\\FoolFuuka\\Controller\\Chan::*')
Foolz\FoolFuuka\Model\Context::loadRoutes#obj.afterRouting¶
->setObject($this)
->setParam('route_collection', $route_collection)
Foolz\FoolFuuka\Model\Media::getLink#exec.beforeMethod¶
->setObject($this)
->setParam('thumbnail', $thumbnail)
Foolz\FoolFuuka\Model\Media::insert#var.media¶
->setParam('dimensions', $dimensions)
->setParam('file', $file)
->setParam('name', $name
->setParam('path', $path)
->setParam('hash', $hash)
->setParam('size', $size)
->setParam('time', $time)
->setParam('media_orig', $media_orig)
->setParam('preview_orig', $preview_orig)
Foolz\FoolFuuka\Model\Media::insert#exec.createThumbnail¶
->setObject($this)
->setParam('is_op', $is_op)
->setParam('media', $media)
->setParam('thumb', $thumb)
->setParam('thumb_width', $thumb_width)
->setParam('thumb_height', $thumb_height)
->setParam('exec', $exec)
Foolz\FoolFuuka\Model\MediaFactory::forgeFromUpload#var.config¶
->setParam('ext_whitelist', [])
->setParam('mime_whitelist', [])
Foolz\FoolFuuka\Model\RadixCollection::structure#var.structure¶
->setParam('structure', $structure)
Foolz\FoolFuuka\Model\RadixCollection::preload#var.radixes¶
->setObject($this)
->setParam('preloaded_radixes', $this->preloaded_radixes)
Contribute¶
Coding Guidelines¶
FoolFuuka follows the PSR-0 and PSR-0 coding standards. In addition to these standards, the guidelines listed below must be followed as well:
- Function and Control Structure opening { MUST BE on a seperate line
IRC Channel¶
We have an IRC channel on the IRCHighWay network that can be used to discuss issues, feature requests, and various other related topics at #fooldriver.
Issue Tracker¶
You can find our issue tracker at our FoolFuuka GitHub repository.