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-autoloader
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 theBoards
section - Set the
Boards Database
field to the same database name used in theasagi.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 theBoards
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 2.1.0
$ 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-autoloader
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-autoloader
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.