Configuration

All options live in config.php (generated by setup.php). Edit the file with any text editor, or use the built-in editor at admin.php?cfg=1 — four tabs, help text, dropdowns, shipped defaults and validation, described in Admin & Settings. Defaults reproduce a standard 9-seat cash table (blinds 10/20, 1000 starting chips).

Storage

ConstantTypeDefaultDescription
POKER_DATA_DIRstring'data' Writable data folder (users, tables, hands, logs). Relative values are resolved from the application folder, so 'data' means /data; an absolute path is also accepted and is written that way by older installers.

Table defaults

ConstantTypeDefaultDescription
POKER_SEATSint9 Seats per table (2–9). The client reads this value automatically. It can be changed at any time and the saved table is resized on the next request, keeping every stack:
  • more seats — empty chairs are added and the hand in progress continues;
  • fewer seats — the extra chairs are removed and the hand continues, unless a player who is in that hand sits on a removed chair (or the turn/blinds point there). Only then that hand is cancelled and every player gets back exactly what he put into it; the next hand starts on the new size.
Reload the page after the change (the size is read when the page loads).
POKER_START_CHIPSint1000Starting stack and free rebuy amount.
POKER_SBint10Default small blind for new tables.
POKER_BBint20Default big blind for new tables.
POKER_TURN_MSint30000Thinking time per turn, in milliseconds.
POKER_NEXT_HAND_MSint10000Pause between hands (ms).
POKER_AWAY_MSint120000Disconnect threshold before a player counts as away (ms).
POKER_AWAY_REMOVE_MSint600000Remove a sitting-out player after this long (ms).
POKER_RUNOUT_MSint3000Pause between streets during an all-in run-out (ms).
POKER_SHOW_MSint3000Pause after the river before declaring the winner (ms).

Tournament

Defaults for the tournament dialog. Players can change every value per tournament in the vote dialog; these are only the starting values. See Tournament Mode for the full behaviour.

ConstantTypeDefaultDescription
POKER_TOURNEY_ENABLEDbooltrue Show the 🏆 Tournament button. false = cash-only game.
POKER_TOURNEY_START_CHIPSint1500 Starting stack = buy-in, taken from every account when the tournament starts.
POKER_TOURNEY_SB / POKER_TOURNEY_BBint10 / 20 Blinds of the first level.
POKER_TOURNEY_LEVEL_MINint5 Minutes per blind level. The ladder follows the starting BB: 1x, 1.5x, 2.5x, 5x, 7.5x, 10x …
POKER_TOURNEY_REBUYbooltrue Rebuys allowed at all (the number and the window are below).
POKER_TOURNEY_START_SECint30 Countdown after the vote, in seconds (the tournament starts between two hands).
POKER_TOURNEY_PAYOUTstring'winner' winner = all to 1st · percent = by percentage · fixed = fixed amounts.
POKER_TOURNEY_PAYOUT_LISTstring'50/30/20' Places used by percent / fixed, e.g. 50/30/20 or 500/300/200.
POKER_TOURNEY_LATEint0 Late registration window (0 = closed).
POKER_TOURNEY_UNITstring'levels' Unit for the late-reg and rebuy windows: levels or minutes.
POKER_TOURNEY_REBUYSint1 Rebuys per player (0 = none, 99 = unlimited).
POKER_TOURNEY_REBUY_UNTILint0 End of the rebuy window in the unit above (0 = whole tournament).
POKER_TOURNEY_REBUY_SECint30 Seconds to answer the rebuy offer. No answer = eliminated (the table waits meanwhile).
POKER_TOURNEY_BREAK_EVERYint0 Break every N minutes of play (0 = no breaks).
POKER_TOURNEY_BREAK_MINint5 Length of a break, in minutes.
POKER_TOURNEY_BREAK_MODEstring'every' every = every N minutes of play · clock = at :MM of every hour.
POKER_TOURNEY_BREAK_ATint55 The :MM minute used by the clock mode.
Prize pool is every chip in play (stacks + bets + pot); the winner is credited to his account once, at the end. Rounding leftovers from a percentage or fixed split go to 1st place, so the payouts always add up to the pool.

Room

ConstantTypeDefaultDescription
POKER_DEFAULT_ROOMstring'MonteCarlo' Name of the table opened when the address has no #Room (2–20 chars, letters/digits/underscore/dash). This table is always playable.
POKER_ROOMSarraynot shipped (empty) Extra rooms that may be played, one code per entry, e.g. define('POKER_ROOMS', ['London', 'Paris']);. It is a whitelist: a link such as index.php#Vegas plays the default table while Vegas is not listed, so a table is never created just because somebody typed a URL. Removing a code closes that room gracefully — the current hand is finished, the stacks are settled and the table is parked; adding the code back reopens it with the same stacks. Managed as chips in the Table & Rooms tab (Admin & Settings).
POKER_BOT_NAMESarray8 English names Names used when a bot is seated (the first unused name is picked).

Features

ConstantTypeDefaultDescription
POKER_HISTORY_ENABLEDbooltrueRecord hands and enable replay.
POKER_HISTORY_MAX_HANDSint50Hands kept per room (0 = unlimited).
POKER_HISTORY_LIST_DEFAULTint50Hands listed to a player by default.
POKER_HISTORY_LIST_MAXint50Hard cap for the hands list.
POKER_HISTORY_SCAN_MAXint60Max hand files inspected while building a list.
POKER_CHAT_ENABLEDbooltrueEnable in-game chat (the panel is hidden when false).
POKER_BOTS_ALLOWEDbooltrue Bots are allowed at the table. false hides every bot control, refuses addbot and hides the whole AI card in the settings page.
POKER_BOTS_ADD_BY_PLAYERSbooltrue Players may seat a bot on an empty chair with 🤖 Add bot. false leaves the button visible only to the admin observer and answers Only the admin can add bots to everybody else.
POKER_BOT_STYLES_ENABLEDbooltrue Bot personalities (Rock / TAG / LAG / Station) plus a personality-aware thinking time. The archetype is drawn from the bot's own id when it sits down, so nobody picks it and it never changes while the bot plays. false makes every bot play the identical baseline engine again (fixed 1.5–2.8 s wait, no style deltas). See User Guide → Bot personalities.
POKER_BLINDS_BY_PLAYERSbooltrue Players may change the table blinds with the ⚙️ Blinds button. false removes the button and answers Changing the blinds is disabled; the admin can still change them.
POKER_RABBIT_ENABLEDbooltrue Rabbit Hunt: when a hand ends by fold-out, reveal the cards that would have come next (5 / 2 / 1 depending on the street). false disables the reveal, its log line and the animation completely. See User Guide.
POKER_RABBIT_MSint3500 How long the Rabbit Hunt cards stay on screen before they fade out (ms).
POKER_RABBIT_SOUNDbooltrue Short "pop" played as each Rabbit Hunt card flips. Works on top of the player's own 🔊 Sound ON/OFF button — false here disables it for everybody.
POKER_HAND_METER_ENABLEDbooltrue Live hand-strength bar under the hand name (0–100% against the players still in the pot, calculated in the browser). false hides the bar and skips the calculation completely.
POKER_TABLE_INFO_ENABLEDbooltrue Small badge in the top-left corner of the table: how many players are seated (👤 3 online) and how many of them are bots (🤖 2 bots, hidden while no bot is seated). false hides the badge completely.

Chat

ConstantTypeDefaultDescription
POKER_CHAT_MAXint50Messages kept per room.
POKER_CHAT_MAX_LENint200Max characters per message.
POKER_CHAT_MIN_GAP_MSint700Anti-flood delay between a player's own messages (ms).
POKER_BANNED_EXTRAarray[] Extra banned words merged with the built-in list. See below.

Adding your own banned words

Add words to POKER_BANNED_EXTRA (the built-in list is always applied):

define('POKER_BANNED_EXTRA', ['word1', 'word2', 'word3']);

The censor also matches common separators and "leet" substitutions (e.g. f.u.c.k, sh1t).

Avatars / Countries

ConstantTypeDefaultDescription
POKER_AVATAR_DIRstring'assets/avatars' Web-relative folder with numbered avatar images (1.jpg, 2.png, …). Do not use an absolute path — it is also used as the image URL.
POKER_AVATAR_MAXint50How many avatars the picker offers.
POKER_FLAG_DIRstring'assets/flags' Web-relative folder with 2-letter flag files (ro.svg, de.png, …).

The default avatars, flags, sounds and countries.json ship inside assets/. They are product files: updates replace them, and the installer never writes into data/ for them. If you keep your own set, point these two constants at it (for example 'data/avatars'); the shipped folder stays as a fallback, and a file with the same number or country code in your folder wins.

Themes — Google Fonts

Most of the bundled themes load a display font from Google Fonts via a CSS @import at the top of their theme.css (14 of the 15 themes — all except classic). This is optional and only affects the visual style of those themes; the game works fine without it.

Making the game 100% offline

If your host blocks external requests, or you simply want zero external calls, open each theme's theme.css and remove the first line:

@import url('https://fonts.googleapis.com/css2?family=...');

Then set the display font in the same file's :root block to a system stack:

--font-display: Georgia, 'Times New Roman', serif;
--font-ui:      'Segoe UI', system-ui, -apple-system, sans-serif;

The theme then falls back to safe system fonts with a similar look. No other change is needed — no PHP edit, no re-install. To list every theme that makes an external call:

findstr /S /I "fonts.googleapis.com" assets\themes\*.css

Self-hosting the fonts

You can also download the font files (WOFF2) from fonts.google.com and place them in assets/themes//fonts/, then replace the @import line with a local @font-face block that points at those files.

Security

ConstantTypeDefaultDescription
POKER_SESSION_NAMEstring'poker_session'PHP session cookie name (shared by index.php and api.php).
POKER_LOGIN_MAX_ATTEMPTSint5Login/register attempts allowed per IP per window.
POKER_LOGIN_LOCKOUT_SECint900Rate-limit window in seconds (900 = 15 minutes).
POKER_CSRF_ENABLEDbooltrueValidate a CSRF token on every state-changing action.
POKER_HTTPS_ONLYboolfalseWhen true: session cookie becomes Secure + SameSite=Strict. Enable on production.
POKER_ADMIN_HASHstring'' bcrypt hash of the admin.php password. Written by setup.php (asked at install; change it there under "Admin password"). Empty means the panel refuses to open — there is no built-in password. Do not edit it by hand: an invalid hash locks the panel, and the recovery is running setup.php again.

Enabling HTTPS

define('POKER_HTTPS_ONLY', true);

Then uncomment the HTTPS redirect block in the root .htaccess after your certificate is live.

Card randomness

There is no POKER_* option for it, on purpose: the deck is always shuffled with PHP's random_int() (CSPRNG, OS entropy) inside a Fisher–Yates loop, so a misconfigured site can never silently fall back to rand()/mt_rand() and become predictable. Details in Fair deal & card randomness.

Debug

ConstantTypeDefaultDescription
POKER_DEBUGboolfalse true shows PHP errors in the browser (development only). false logs them to file. Keep false on production.
POKER_LOG_DIRstring'data/logs' Where php-errors.log is written when debugging is off. Relative values are resolved from the application folder; an absolute path is also accepted.

AI Bots (DeepSeek) — optional

The bots are 100% rule-based by default (pure PHP: GTO ranges, Monte-Carlo equity, pot odds, outs, board texture and an opponent model in data/bot_stats.json). You can optionally add a DeepSeek layer that judges on top of those numbers: it receives the engine's own equity / pot-odds / outs plus the opponent stats and the rule engine's intended line, and may override it. Every answer is validated and "leashed", and on any error or timeout the rule engine's action stands — an action is never illegal and the table never freezes.

The whole integration is a single file: bot/bot_ai.php. With an empty API key (or POKER_AI_ENABLED = false) it is a complete no-op and costs nothing. setup.php sets ENABLED = true and the key automatically when you enter one during install.

Getting a DeepSeek API key

  1. Create an account at platform.deepseek.com.
  2. Add credit — DeepSeek is pay-per-use (each bot decision costs a fraction of a cent).
  3. Open the API keys section and create a new key (it starts with sk-).
  4. Put it in config.php:
    define('POKER_AI_ENABLED', true);
    define('POKER_AI_API_KEY', 'sk-...');
    …or simply enter it in the installer (setup.php) — it sets the key and POKER_AI_ENABLED = true for you at install time.
  5. Keep the key secret: do not share it or post it publicly. If it leaks, delete it in the dashboard and create a new one. An empty key turns the whole AI layer off.

The key is only ever sent to POKER_AI_ENDPOINT (DeepSeek by default) and is never written to the logs — check with the browser/API keys page that no other app uses it.

Checking the remaining credit

Open the settings page admin.php?cfg=1 (admin password). On the right of the AI BOTS (DeepSeek) card header there is a green badge with the account balance, for example 2.16 USD. It is read from DeepSeek's own GET https://api.deepseek.com/user/balance with the configured key, so it is the real remaining credit, not an estimate.

Full settings block

// ============ AI BOTS (DeepSeek) ============
// Empty key (or POKER_AI_ENABLED=false) keeps the bots fully rule-based and free.
// Setup sets ENABLED=true + the key automatically when you enter one.
define('POKER_AI_ENABLED',        false);
define('POKER_AI_API_KEY',        '');
define('POKER_AI_ENDPOINT',       'https://api.deepseek.com/v1/chat/completions');
define('POKER_AI_MODE',           'hybrid');
define('POKER_AI_MODEL',          'deepseek-flash');
define('POKER_AI_MODEL_BIG',      'deepseek-v4-pro');
define('POKER_AI_THINKING',       'disabled');
define('POKER_AI_THINKING_BIG',   'disabled');
define('POKER_AI_TRIGGER',        'marginal');
// Use the AI only when a real (human) player is actually playing at the table.
// A human on sit-out (away) or still waiting for the BB does not count, so games
// with only bots (or an away human) stay fully rule-based and free.
define('POKER_AI_ONLY_WITH_HUMANS', true);
define('POKER_AI_SAMPLE_PCT',     25);
define('POKER_AI_MARGIN_BAND',    0.10);
define('POKER_AI_BIGBET_PCT',     0.25);
define('POKER_AI_LEASH',          'normal');
define('POKER_AI_MIN_CONFIDENCE', 0.55);
define('POKER_AI_TEMPERATURE',    0.3);
define('POKER_AI_MAX_TOKENS',     200);
define('POKER_AI_TIMEOUT_MS',     20000);
define('POKER_AI_MAX_CALLS_PER_HAND', 12);
define('POKER_AI_PREFETCH',       false);
define('POKER_AI_SSL_VERIFY',     true);
define('POKER_AI_LOG',            false);
define('POKER_AI_DEBUG',          false);
define('POKER_AI_PHP_BIN',        '');
ConstantTypeDefaultDescription
POKER_AI_ENABLEDboolfalseMaster switch. false = bots stay fully rule-based.
POKER_AI_API_KEYstring''DeepSeek API key — create one at platform.deepseek.com (API keys). Empty = the whole layer is off.
POKER_AI_ENDPOINTstringdeepseek.com/v1/chat/completionsOpenAI-compatible chat endpoint.
POKER_AI_MODEstring'hybrid'hybrid | ai_first | advisor — see Modes.
POKER_AI_MODELstring'deepseek-flash'Model for normal spots (fast, cheap).
POKER_AI_MODEL_BIGstring'deepseek-v4-pro'Model for big spots (the extended "Pro" tier). Must be an ID the provider accepts — this API supports deepseek-flash and deepseek-v4-pro.
POKER_AI_THINKINGstring'disabled'disabled | enabled for normal spots (thinking is slower).
POKER_AI_THINKING_BIGstring'disabled'Thinking for big spots. enabled is much slower — raise the timeout if you use it.
POKER_AI_TRIGGERstring'marginal'When the AI is consulted: marginal | river | bigbet | sample | all.
POKER_AI_ONLY_WITH_HUMANSbooltrueConsult the AI only when a real (human) player is actually playing. A seated human on sit-out (away) or still waiting for the BB (waitBB) is not dealt in and does not count, so bots-only games — or a game where the human sat out — stay fully rule-based and free. Humans-vs-humans never calls the AI anyway.
POKER_AI_SAMPLE_PCTint25Percentage of decisions used by the sample trigger.
POKER_AI_MARGIN_BANDfloat0.10marginal: how close (equity vs pot odds) counts as a close decision.
POKER_AI_BIGBET_PCTfloat0.25bigbet: toCall / stack threshold.
POKER_AI_LEASHstring'normal'How far the AI may deviate from the engine: strict | normal | loose.
POKER_AI_MIN_CONFIDENCEfloat0.55Answers below this confidence are ignored (engine line kept).
POKER_AI_TEMPERATUREfloat0.3Sampling temperature (non-thinking calls only).
POKER_AI_MAX_TOKENSint200Reply budget (the answer is a tiny JSON object).
POKER_AI_TIMEOUT_MSint20000Hard per-call timeout. On expiry the engine line is used. Raise it for thinking models.
POKER_AI_MAX_CALLS_PER_HANDint12Cost guard: max AI calls per hand (0 = unlimited).
POKER_AI_PREFETCHboolfalseWarm the answer during the bot's "thinking" window (needs proc_open + a PHP CLI binary).
POKER_AI_SSL_VERIFYbooltrueVerify the TLS certificate. false only for local debugging.
POKER_AI_LOGboolfalseAppend a compact decision log to data/bot_ai_log.json.
POKER_AI_DEBUGboolfalseWrite the raw request + response to data/bot_ai_debug.log (verbose — turn off in normal use).
POKER_AI_PHP_BINstring''PHP CLI path used by prefetch (auto-detected when empty).

Modes

Triggers (when the AI is consulted, hybrid/advisor)

Leash (how far the AI may deviate)

Logs

Both folders are inside the protected data/ directory — download them via FTP/SSH, they are not web-accessible.

AI troubleshooting

Rollback: set POKER_AI_ENABLED = false (or empty the key). The bots return to 100% rule-based immediately — no other change needed.

Allowed ranges

The settings page (Admin & Settings) enforces these limits on the server and mirrors them as min/max in the browser; a value outside them is refused and nothing is written to config.php. Decimals are kept as typed.

Option(s)Allowed
POKER_SEATS2–9
POKER_START_CHIPS, POKER_SB1 – 1,000,000
POKER_BB2 – 1,000,000 and bigger than POKER_SB
POKER_AVATAR_MAX, POKER_LOGIN_MAX_ATTEMPTS1–1000
POKER_LOGIN_LOCKOUT_SEC0 – 86,400 (0 = off)
POKER_HISTORY_MAX_HANDS0 – 100,000 (0 = unlimited)
POKER_HISTORY_LIST_DEFAULT, _LIST_MAX, _SCAN_MAX1–1000
POKER_CHAT_MAX / POKER_CHAT_MAX_LEN0–10,000 / 1–2000
every other *_MS0 – 3,600,000 ms (1 hour)
POKER_AI_SAMPLE_PCT0–100
POKER_AI_MARGIN_BAND, _BIGBET_PCT, _MIN_CONFIDENCE0–1
POKER_AI_TEMPERATURE0–2
POKER_AI_MAX_TOKENS32–4000
POKER_AI_TIMEOUT_MS1,000 – 120,000 ms (1–120 s)
POKER_AI_MAX_CALLS_PER_HAND0–100 (0 = unlimited)
POKER_DEFAULT_ROOM and the POKER_ROOMS codes letters, digits, -, _, max 20 — see Admin & Settings for the chips editor
any other number0 or more
any textmax 2000 characters

Common examples

Change the blinds and stack

define('POKER_SB',          5);
define('POKER_BB',          10);
define('POKER_START_CHIPS', 2000);

Blinds apply to new tables; an existing table keeps its blinds (a seated player can change them with the Blinds control).

Run a 6-max table

define('POKER_SEATS', 6);

The client reads the seat count from window.POKER_CFG, so no other change is needed.

Turn chat off

define('POKER_CHAT_ENABLED', false);

Enable the AI bots

define('POKER_AI_ENABLED', true);
define('POKER_AI_API_KEY', 'sk-...');   // your DeepSeek key

Create the key at platform.deepseek.com (section API keys) and keep some credit on the account — DeepSeek is pay-per-use.

Start with the defaults (hybrid + marginal). While tuning, set POKER_AI_DEBUG = true to write the raw request/response to data/bot_ai_debug.log, and turn it back off once it behaves as expected.

Make the big-spot model faster

define('POKER_AI_MODEL_BIG', 'deepseek-flash');   // same fast model for every spot

Or keep a stronger model but avoid thinking latency: define('POKER_AI_THINKING_BIG', 'disabled');