Progress
0%

Introduction to Server-Side Scripting (PHP I)

Master PHP fundamentals: client-server model, variables, control structures, and arrays.

5
Sections
Client-Server · PHP Basics · Variables · Control Structures · Arrays
20
Flashcard Terms
Key vocabulary and syntax patterns from the chapter
15
Quiz Questions
Test your understanding with code-tracing and concept questions
Client-Server Request-Response Cycle
🖥
User enters URL
CLIENT
→
📤
HTTP GET Request
CLIENT
→
🔍
Server looks up file
SERVER
→
⚙️
PHP Interpreter runs
SERVER
→
📥
Browser renders HTML
CLIENT
Key Concepts at a Glance
What is the difference between a static and dynamic web page?▼
A static web page (HTML/CSS only) returns the same content to every user at any time. A dynamic web page uses server-side scripting (like PHP) to generate different content based on logic — for example, showing "Good Morning" or "Good Afternoon" depending on the time of day.
How does a PHP file differ from an HTML file?▼
An HTML file is returned directly to the browser. A PHP file is first processed by the PHP Interpreter on the server — it executes any code between <?php and ?> tags, then sends a resulting HTML file back to the client. The browser never sees PHP code.
What is the role of the PHP Interpreter?▼
The PHP Interpreter is software installed on the web server. It reads a .php file, executes all PHP code blocks, copies all non-PHP code directly, and produces a resulting .html output that is sent back to the client.
What are the 4 data types in PHP?▼
Integer — whole numbers (e.g., 0, 1, -2, 1000)
Float — real/decimal numbers (e.g., 1.23, -2.0, 3.14)
Boolean — True or False (no quotes!)
String — text enclosed in double quotes (e.g., "Hello World")
What is the difference between an array and an associative array?▼
A regular array uses numeric indexes starting from 0 (e.g., $friends[0]). An associative array uses string indexes (keys) that you define (e.g., $user["name"]). Associative arrays are used to store related attributes of an entity.

PHP Fundamentals

Explore the building blocks of PHP server-side scripting.

🌐
PHP File Syntax
PHP code is enclosed between <?php and ?>. Every statement ends with a semicolon. Non-PHP code (HTML) is copied directly to output.
<?php echo "Hello World!"; ?>
📦
Variables & Data Types
Variables start with $. Four data types: Integer, Float, Boolean, String.
$name = "Alice"; $age = 18; $score = 95.5; $pass = True;
🔗
String Operations
Use . to concatenate strings. Use {$var} inside double-quoted strings for variable parsing. Escape special chars with \.
$n = "Bob"; echo "Hello {$n}!"; // Hello Bob!
🔀
If-Else & Elseif
Conditional logic uses if(), else, and elseif(). Blocks must be enclosed in { }. Use == to compare, not =.
if($hour < 12){ echo "Morning"; } else { echo "Afternoon"; }
🔁
Loops: while & for
while repeats while condition is true. for loops define initialise, condition, and afterthought in one line. Use foreach for arrays.
for($i=1; $i<=5; $i++){ echo "{$i}<br>"; }
📋
Arrays & Associative Arrays
Arrays store multiple values. Add with $arr[] = val. Get length with count(). Associative arrays use string keys.
$user["name"] = "Ken"; $user["age"] = 16; echo $user["name"];
🔢
Arithmetic Operators
Standard operators: + - * /. Modulo % returns remainder. Exponentiation **. Use floor() for floor division.
$r = 9 % 4; // 1 $p = 2 ** 8; // 256 $f = floor(9/4); // 2
📝
Comments in PHP
Single-line comments use // or #. Multi-line comments use /* ... */. HTML comments outside PHP tags are copied to output.
// Single-line comment /* Multi-line comment */ <?php $x = 5; ?>

PHP Cheat Sheet

Quick reference for syntax, operators, and built-in functions covered in Chapter 2.

Variables & Data Types
ConceptSyntax / ExampleNotes
Declare variable$name = "Alice";Must start with $, then _ or letter
Integer$n = 42;Whole numbers, positive or negative
Float$pi = 3.14;Decimal / real numbers
Boolean$ok = True;No quotes — True/False
String$s = "hello";Use double quotes ""
Operators
OperatorExampleResult / Meaning
+ - * /$c = $a + $b;Arithmetic
%9 % 4 → 1Modulo (remainder)
**2 ** 8 → 256Exponentiation
+= -=$a += $b;Combined assignment
++ --$a++;Increment / Decrement
."Hi" . $nameString concatenation
== != < > <= >=$x == $yRelational operators
and / && | or / || !$a and $bLogical operators
Control Structures
StructurePHP SyntaxNotes
if-elseif($x > 0){ ... } else { ... }Condition must be boolean expression
elseifelseif($x == 0){ ... }Checks additional conditions
while loopwhile($i < 10){ $i++; }Checks condition before each iteration
for loopfor($i=0; $i<5; $i++){ ... }Init; condition; afterthought
foreach loopforeach($arr as $v){ ... }Iterates over array elements
Arrays
OperationCodeNotes
Create empty$arr = [];Empty array
Create with values$arr = ["a","b","c"];Index starts from 0
Access element$arr[1]Returns "b"
Add element$arr[] = "d";Appends to end
Get lengthcount($arr)Returns number of elements
Associative array$user["name"] = "Ken";String index / key
String Escaping
CharacterEscapeExampleOutput
" (double quote)\"echo "It is \"great\"";It is "great"
\ (backslash)\\echo "A\\B";A\B
$ (dollar sign)\$echo "Cost: \$50";Cost: $50

Flashcards

Click a card to reveal the definition. Use the arrows to navigate.

1 / 12
TERM / CONCEPT
Client
↕ Click to flip
DEFINITION
Loading...

Quiz

Test your PHP knowledge with code-tracing and concept questions.

Q1 / 15 Score: 0
' }, zh: { term:'HTTP回應 (HTTP Response)', def:'伺服器發送回的消息,包含狀態碼、內容類型和回應主體(HTML文件)。', code:'Status: 200 OK\nContent-Type: text/html\nBody: ...' }}, { en: { term:'Static Web Page', def:'A web page using only HTML/CSS that returns the same content to every user regardless of when or who requests it.', code:'' }, zh: { term:'靜態網頁 (Static Web Page)', def:'只使用HTML/CSS的網頁,無論何時或誰請求,都返回相同的內容。', code:'' }}, { en: { term:'Dynamic Web Page', def:'A web page that uses server-side scripting to generate different content based on programmed logic (e.g., time of day, user input).', code:'' }, zh: { term:'動態網頁 (Dynamic Web Page)', def:'使用伺服器端腳本根據編程邏輯生成不同內容的網頁(如一天中的時間、用戶輸入)。', code:'' }}, { en: { term:'PHP Interpreter', def:'Software on the web server that processes .php files — executes PHP code blocks and copies non-PHP code to generate a resulting HTML file.', code:'' }, zh: { term:'PHP解譯器 (PHP Interpreter)', def:'網頁伺服器上的軟件,處理.php文件——執行PHP代碼塊並複製非PHP代碼以生成HTML文件。', code:'' }}, { en: { term:'echo', def:'PHP statement that outputs a string to the resulting HTML file.', code:'' }, zh: { term:'echo', def:'PHP語句,向生成的HTML文件輸出字串。', code:'' }}, { en: { term:'Variable Declaration', def:'PHP variables start with $, followed by an underscore or letter, then any alphanumeric characters. Always initialise on declaration.', code:'$name = "Alice";\n$_age = 18;\n$score2 = 95.5;' }, zh: { term:'變數宣告 (Variable Declaration)', def:'PHP變數以$開頭,後跟下劃線或字母,然後是任意字母數字字符。宣告時始終初始化。', code:'$name = "Alice";\n$_age = 18;\n$score2 = 95.5;' }}, { en: { term:'String Concatenation (.)', def:'The dot operator (.) joins two strings into one. Cannot use + for strings in PHP.', code:'$first = "Hello";\n$second = " World";\necho $first . $second;' }, zh: { term:'字串連接(.)', def:'點運算子(.)將兩個字串連接成一個。PHP中字串不能使用+。', code:'$first = "Hello";\n$second = " World";\necho $first . $second;' }}, { en: { term:'Variable Parsing', def:'Inserting a variable\'s value directly into a double-quoted string using {$var} syntax.', code:'$name = "Emily";\necho "Welcome {$name}!";' }, zh: { term:'變數解析 (Variable Parsing)', def:'使用{$var}語法將變數值直接插入雙引號字串中。', code:'$name = "Emily";\necho "Welcome {$name}!";' }}, { en: { term:'Modulo Operator (%)', def:'Returns the remainder when one number is divided by another. Useful for checking divisibility.', code:'$r = 9 % 4; // 1\n// 9 = 4×2 + remainder 1' }, zh: { term:'模數運算子(%)', def:'返回一個數除以另一個數的餘數。用於檢查整除性。', code:'$r = 9 % 4; // 1\n// 9 = 4×2 + 餘數1' }}, { en: { term:'foreach Loop', def:'Iterates through each element of an array in index order. The loop variable takes the value of each element.', code:'foreach($class as $m){\n echo "{$m}
";\n}' }, zh: { term:'foreach 迴圈', def:'按索引順序遍歷陣列的每個元素。循環變量取每個元素的值。', code:'foreach($class as $m){\n echo "{$m}
";\n}' }}, { en: { term:'count()', def:'Built-in PHP function that returns the number of elements in an array.', code:'$friends = ["A","B","C"];\n$n = count($friends); // 3' }, zh: { term:'count()', def:'內建PHP函式,返回陣列中的元素數量。', code:'$friends = ["A","B","C"];\n$n = count($friends); // 3' }}, { en: { term:'Associative Array', def:'An array where each element is stored as a key-value pair with a string key defined by the developer.', code:'$user["name"] = "Ken";\n$user["age"] = 16;\necho $user["name"]; // Ken' }, zh: { term:'關聯陣列 (Associative Array)', def:'每個元素以開發者定義的字串鍵-值對存儲的陣列。', code:'$user["name"] = "Ken";\n$user["age"] = 16;\necho $user["name"]; // Ken' }}, ]; var quizData = [ { en: { q: 'Which of the following is a valid PHP variable name?', code:'', opts: ['$21count','$_myVar','$class@22','ndms'], ans: 1, fb: '$_myVar is valid: starts with $, first char is underscore, then letters/numbers.' }, zh: { q: '以下哪個是有效的PHP變數名?', code:'', opts: ['$21count','$_myVar','$class@22','ndms'], ans: 1, fb: '$_myVar 有效:以$開頭,第一個字符是下劃線,然後是字母/數字。' }}, { en: { q: 'What will the following PHP code output?', code:'', opts: ['2','1','2.25','36'], ans: 1, fb: '9 % 4 = 1 (remainder when 9 is divided by 4 is 1).' }, zh: { q: '以下PHP代碼將輸出什麼?', code:'', opts: ['2','1','2.25','36'], ans: 1, fb: '9 % 4 = 1(9除以4的餘數是1)。' }}, { en: { q: 'What does the PHP Interpreter do when processing a .php file?', code:'', opts: ['Sends the .php file directly to the browser','Executes PHP code and copies non-PHP code to generate HTML','Converts PHP to JavaScript','Stores the file in a database'], ans: 1, fb: 'The PHP Interpreter executes PHP blocks and copies HTML code, producing a resulting HTML file sent to the client.' }, zh: { q: 'PHP解譯器處理.php文件時做什麼?', code:'', opts: ['直接將.php文件發送給瀏覽器','執行PHP代碼並複製非PHP代碼以生成HTML','將PHP轉換為JavaScript','將文件存儲在數據庫中'], ans: 1, fb: 'PHP解譯器執行PHP代碼塊並複製HTML代碼,生成發送給客戶端的HTML文件。' }}, { en: { q: 'What is the output of this code?', code:'', opts: ['Welcome $name, today is $day','Welcome Emily, today is Tuesday','Welcome {$name}, today is {$day}','Error — syntax mistake'], ans: 1, fb: 'Variable parsing replaces {$name} and {$day} with their values inside double-quoted strings.' }, zh: { q: '此代碼的輸出是什麼?', code:'', opts: ['Welcome $name, today is $day','Welcome Emily, today is Tuesday','Welcome {$name}, today is {$day}','錯誤 — 語法錯誤'], ans: 1, fb: '變數解析在雙引號字串中將{$name}和{$day}替換為其值。' }}, { en: { q: 'Which HTTP status code means "Successfully processed"?', code:'', opts: ['404','403','200','500'], ans: 2, fb: '200 means successfully processed. 404 = not found, 403 = forbidden, 500 = internal server error.' }, zh: { q: '哪個HTTP狀態碼表示"成功處理"?', code:'', opts: ['404','403','200','500'], ans: 2, fb: '200表示成功處理。404=未找到,403=禁止,500=內部伺服器錯誤。' }}, { en: { q: 'What is wrong with the following code?', code:'', opts: ['Missing semicolon after echo','= should be == for comparison','Missing {} braces','echo should be print'], ans: 1, fb: 'Using = (assignment) instead of == (equality) in an if-condition assigns the value and causes unintended behaviour.' }, zh: { q: '以下代碼有什麼問題?', code:'', opts: ['echo後缺少分號','= 應該是 == 用於比較','缺少{}括號','echo應該是print'], ans: 1, fb: '在if條件中使用=(賦值)而不是==(相等)會賦值並導致意外行為。' }}, { en: { q: 'What does the foreach loop do in PHP?', code:'foreach($class as $m){\n echo "{$m}
";\n}', opts: ['Loops a fixed number of times','Loops while a condition is true','Iterates through each element of an array','Counts the elements of an array'], ans: 2, fb: 'foreach iterates through each element of an array. $m takes the value of each element in turn.' }, zh: { q: 'PHP中的foreach迴圈做什麼?', code:'foreach($class as $m){\n echo "{$m}
";\n}', opts: ['循環固定次數','當條件為真時循環','遍歷陣列的每個元素','計算陣列的元素'], ans: 2, fb: 'foreach遍歷陣列的每個元素。$m依次取每個元素的值。' }}, { en: { q: 'Given $a = 9 and $b = 4, what is the value of $c after: $c = $a ** $b;?', code:'', opts: ['36','6561','13','2.25'], ans: 1, fb: '9 ** 4 = 9⁴ = 9×9×9×9 = 6561. The ** operator is exponentiation.' }, zh: { q: '給定 $a = 9 和 $b = 4,執行 $c = $a ** $b; 後$c的值是什麼?', code:'', opts: ['36','6561','13','2.25'], ans: 1, fb: '9 ** 4 = 9⁴ = 9×9×9×9 = 6561。**運算子是冪運算。' }}, { en: { q: 'How do you add a new element to the end of a PHP array named $arr?', code:'', opts: ['$arr.add("new");','$arr[] = "new";','$arr[end] = "new";','push($arr, "new");'], ans: 1, fb: 'Use $arr[] = value; to append an element to the end of an array in PHP.' }, zh: { q: '如何在名為$arr的PHP陣列末尾添加新元素?', code:'', opts: ['$arr.add("new");','$arr[] = "new";','$arr[end] = "new";','push($arr, "new");'], ans: 1, fb: '使用 $arr[] = value; 在PHP陣列末尾追加元素。' }}, { en: { q: 'What will this code output?', code:'";\n $num += 17;\n }\n?>', opts: ['17 34','17 34 51','17 34 51 68','17'], ans: 1, fb: 'Starting at 17: 17<60 ✓, 34<60 ✓, 51<60 ✓, 68<60 ✗. So outputs 17, 34, 51.' }, zh: { q: '此代碼將輸出什麼?', code:'";\n $num += 17;\n }\n?>', opts: ['17 34','17 34 51','17 34 51 68','17'], ans: 1, fb: '從17開始:17<60 ✓, 34<60 ✓, 51<60 ✓, 68<60 ✗。所以輸出17, 34, 51。' }}, { en: { q: 'What is the index of the first element in a PHP array?', code:'', opts: ['1','0','-1','Depends on the array'], ans: 1, fb: 'Array indexes in PHP start from 0. So $arr[0] is the first element.' }, zh: { q: 'PHP陣列中第一個元素的索引是什麼?', code:'', opts: ['1','0','-1','取決於陣列'], ans: 1, fb: 'PHP中陣列索引從0開始。所以$arr[0]是第一個元素。' }}, { en: { q: 'Which is the correct way to escape a double quote in a PHP string?', code:'echo "She said \\"hello\\"";', opts: ['Use single quotes inside','Add \\\" before each double quote','Use the escape sequence \\"','Both A and C are correct'], ans: 3, fb: 'Both work: single quotes inside ("She said \"hello\"") and escaping with \\". Option A is technically valid but the chapter recommends using \\".' }, zh: { q: '在PHP字串中轉義雙引號的正確方式是什麼?', code:'echo "She said \\"hello\\"";', opts: ['在內部使用單引號','在每個雙引號前加\\\"','使用轉義序列\\"','A和C都正確'], ans: 3, fb: '兩種方法都有效:在內部使用單引號和使用\\"轉義。A在技術上有效,但本章建議使用\\"。' }}, { en: { q: 'What does count($arr) return if $arr = ["a", "b", "c", "d"]?', code:'', opts: ['3','4','0','Error'], ans: 1, fb: 'count() returns the number of elements. $arr has 4 elements: "a","b","c","d".' }, zh: { q: '如果 $arr = ["a", "b", "c", "d"],count($arr) 返回什麼?', code:'', opts: ['3','4','0','錯誤'], ans: 1, fb: 'count()返回元素數量。$arr有4個元素:"a","b","c","d"。' }}, { en: { q: 'In an associative array, what is used as the index of each element?', code:'', opts: ['A number starting from 0','A string defined by the developer','A PHP keyword','An integer auto-assigned by PHP'], ans: 1, fb: 'Associative arrays use string keys (e.g., "name", "age") as indexes, defined by the developer.' }, zh: { q: '在關聯陣列中,每個元素的索引是什麼?', code:'', opts: ['從0開始的數字','開發者定義的字串','PHP關鍵字','PHP自動分配的整數'], ans: 1, fb: '關聯陣列使用字串鍵(如"name"、"age")作為索引,由開發者定義。' }}, { en: { q: 'Which for loop correctly outputs numbers 1 to 5?', code:'', opts: ['for($i=0; $i<5; $i++){ echo $i; }','for($i=1; $i<=5; $i++){ echo $i; }','for($i=1; $i<5; $i++){ echo $i; }','for($i=0; $i<=5; $i++){ echo $i; }'], ans: 1, fb: 'Start at $i=1, loop while $i<=5, increment $i++: outputs 1,2,3,4,5.' }, zh: { q: '哪個for迴圈正確輸出1到5的數字?', code:'', opts: ['for($i=0; $i<5; $i++){ echo $i; }','for($i=1; $i<=5; $i++){ echo $i; }','for($i=1; $i<5; $i++){ echo $i; }','for($i=0; $i<=5; $i++){ echo $i; }'], ans: 1, fb: '從$i=1開始,當$i<=5時循環,遞增$i++:輸出1,2,3,4,5。' }}, ]; var completedQ = new Set(); function setLang(l) { lang = l; document.querySelectorAll('.lang-btn').forEach(function(b,i){ b.classList.toggle('active', (i===0 && l==='en')||(i===1 && l==='zh')); }); applyLang(); loadFlashcard(); loadQuestion(); } function applyLang() { var t = T[lang]; document.getElementById('site-title').textContent = t.siteTitle; var tabs = document.querySelectorAll('.tab-btn'); t.tabs.forEach(function(name, i){ if(tabs[i]) tabs[i].textContent = name; }); var ids = ['tag-overview','title-overview','desc-overview','tag-concepts','title-concepts','desc-concepts', 'tag-cheatsheet','title-cheatsheet','desc-cheatsheet','tag-flashcards','title-flashcards','desc-flashcards', 'tag-quiz','title-quiz','desc-quiz','lbl-progress','lbl-sections','lbl-flashcards-count','lbl-quiz-count', 'detail-sections','detail-flashcards','detail-quiz','flow-title','flow1t','flow2t','flow3t','flow4t','flow5t','faqs-title', 'acc1h','acc2h','acc3h','acc4h','acc5h','cc1t','cc2t','cc3t','cc4t','cc5t','cc6t','cc7t','cc8t', 'ch1h','ch2h','ch3h','ch4h','ch5h','ch-col1','ch-col2','ch-col3','ch-col2b','ch-col3b', 'ch-col2c','ch-col3c','ch-col2d','ch-col3d','ch-col2e','ch-col2f','ch-col3e', 'cht1a','cht1c','cht2a','cht3a','cht3c','cht4a','cht4c','cht5a','cht5c', 'o1','o2','o3','o4','o5','o6','o7','o8','cs1a','cs1c','cs2a','cs2c','cs3a','cs3c','cs4a','cs4c','cs5a','cs5c', 'ar1a','ar1c','ar2a','ar2c','ar3a','ar3c','ar4a','ar4c','ar5a','ar5c','ar6a','ar6c', 'es1a','es2a','es3a', 'btn-prev','btn-next','btn-restart','btn-nextq']; var map = { 'tag-overview':'tagOverview','title-overview':'titleOverview','desc-overview':'descOverview', 'tag-concepts':'tagConcepts','title-concepts':'titleConcepts','desc-concepts':'descConcepts', 'tag-cheatsheet':'tagCheatsheet','title-cheatsheet':'titleCheatsheet','desc-cheatsheet':'descCheatsheet', 'tag-flashcards':'tagFlashcards','title-flashcards':'titleFlashcards','desc-flashcards':'descFlashcards', 'tag-quiz':'tagQuiz','title-quiz':'titleQuiz','desc-quiz':'descQuiz', 'lbl-progress':'lblProgress','lbl-sections':'lblSections','lbl-flashcards-count':'lblFlashcardsCount', 'lbl-quiz-count':'lblQuizCount','detail-sections':'detailSections','detail-flashcards':'detailFlashcards', 'detail-quiz':'detailQuiz','flow-title':'flowTitle', 'flow1t':'flow1','flow2t':'flow2','flow3t':'flow3','flow4t':'flow4','flow5t':'flow5', 'faqs-title':'faqsTitle', 'acc1h':'acc1h','acc2h':'acc2h','acc3h':'acc3h','acc4h':'acc4h','acc5h':'acc5h', 'cc1t':'cc1t','cc2t':'cc2t','cc3t':'cc3t','cc4t':'cc4t','cc5t':'cc5t','cc6t':'cc6t','cc7t':'cc7t','cc8t':'cc8t', 'ch1h':'ch1h','ch2h':'ch2h','ch3h':'ch3h','ch4h':'ch4h','ch5h':'ch5h', 'ch-col1':'chCol1','ch-col2':'chCol2','ch-col3':'chCol3','ch-col2b':'chCol2b','ch-col3b':'chCol3b', 'ch-col2c':'chCol2c','ch-col3c':'chCol3c','ch-col2d':'chCol2d','ch-col3d':'chCol3d', 'ch-col2e':'chCol2e','ch-col2f':'chCol2f','ch-col3e':'chCol3e', 'cht1a':'cht1a','cht1c':'cht1c','cht2a':'cht2a','cht3a':'cht3a','cht3c':'cht3c', 'cht4a':'cht4a','cht4c':'cht4c','cht5a':'cht5a','cht5c':'cht5c', 'o1':'o1','o2':'o2','o3':'o3','o4':'o4','o5':'o5','o6':'o6','o7':'o7','o8':'o8', 'cs1a':'cs1a','cs1c':'cs1c','cs2a':'cs2a','cs2c':'cs2c','cs3a':'cs3a','cs3c':'cs3c', 'cs4a':'cs4a','cs4c':'cs4c','cs5a':'cs5a','cs5c':'cs5c', 'ar1a':'ar1a','ar1c':'ar1c','ar2a':'ar2a','ar2c':'ar2c','ar3a':'ar3a','ar3c':'ar3c', 'ar4a':'ar4a','ar4c':'ar4c','ar5a':'ar5a','ar5c':'ar5c','ar6a':'ar6a','ar6c':'ar6c', 'es1a':'es1a','es2a':'es2a','es3a':'es3a', 'btn-prev':'btnPrev','btn-next':'btnNext','btn-restart':'btnRestart','btn-nextq':'btnNextQ' }; var descMap = { 'acc1b':'acc1b','acc2b':'acc2b','acc3b':'acc3b','acc4b':'acc4b','acc5b':'acc5b', 'cc1d':'cc1d','cc2d':'cc2d','cc3d':'cc3d','cc4d':'cc4d','cc5d':'cc5d','cc6d':'cc6d','cc7d':'cc7d','cc8d':'cc8d', }; Object.keys(map).forEach(function(id) { var el = document.getElementById(id); if(el && t[map[id]] !== undefined) el.textContent = t[map[id]]; }); Object.keys(descMap).forEach(function(id) { var el = document.getElementById(id); if(el && t[descMap[id]] !== undefined) el.innerHTML = t[descMap[id]]; }); document.getElementById('fc-front-label').textContent = t.fcFrontLabel; document.getElementById('fc-back-label').textContent = t.fcBackLabel; document.getElementById('fc-hint').textContent = t.fcHint; } function switchTab(name) { document.querySelectorAll('.section').forEach(function(s){ s.classList.remove('active'); }); document.querySelectorAll('.tab-btn').forEach(function(b){ b.classList.remove('active'); }); document.getElementById('sec-'+name).classList.add('active'); document.getElementById('tab-'+name).classList.add('active'); } function toggleAccordion(el) { el.classList.toggle('open'); } function loadFlashcard() { var fc = flashcards[fcIdx][lang]; document.getElementById('fc-inner').classList.remove('flipped'); fcFlipped = false; document.getElementById('fc-term').textContent = fc.term; document.getElementById('fc-def').textContent = fc.def; var codeEl = document.getElementById('fc-code'); if(fc.code) { codeEl.textContent = fc.code; codeEl.style.display = 'block'; } else { codeEl.style.display = 'none'; } document.getElementById('fc-counter').textContent = (fcIdx+1) + ' / ' + flashcards.length; } function flipCard() { fcFlipped = !fcFlipped; document.getElementById('fc-inner').classList.toggle('flipped', fcFlipped); } function fcNav(dir) { fcIdx = (fcIdx + dir + flashcards.length) % flashcards.length; loadFlashcard(); } function loadQuestion() { if(quizIdx >= quizData.length) { showFinal(); return; } var q = quizData[quizIdx][lang]; document.getElementById('quiz-counter').textContent = 'Q'+(quizIdx+1)+' / '+quizData.length; document.getElementById('quiz-q').textContent = q.q; var codeEl = document.getElementById('quiz-code'); if(q.code){ codeEl.textContent = q.code; codeEl.style.display='block'; } else { codeEl.style.display='none'; } var optsEl = document.getElementById('quiz-opts'); optsEl.innerHTML = ''; var letters = ['A','B','C','D']; q.opts.forEach(function(opt,i){ var btn = document.createElement('button'); btn.className = 'quiz-opt'; btn.innerHTML = ''+letters[i]+' '+opt; btn.onclick = function(){ checkAnswer(i, btn); }; btn.disabled = false; optsEl.appendChild(btn); }); document.getElementById('quiz-feedback').className = 'feedback-msg'; document.getElementById('quiz-feedback').textContent = ''; document.getElementById('btn-nextq').style.display = 'none'; answered = false; updateScoreBadge(); } function checkAnswer(chosen, btn) { if(answered) return; answered = true; var q = quizData[quizIdx][lang]; var opts = document.querySelectorAll('.quiz-opt'); opts.forEach(function(o){ o.disabled = true; }); var fb = document.getElementById('quiz-feedback'); if(chosen === q.ans) { btn.classList.add('correct'); fb.className = 'feedback-msg correct'; fb.textContent = (lang==='en' ? '✓ Correct! ' : '✓ 正確!') + q.fb; if(!completedQ.has(quizIdx)){ quizScore++; completedQ.add(quizIdx); } } else { btn.classList.add('wrong'); opts[q.ans].classList.add('correct'); fb.className = 'feedback-msg wrong'; fb.textContent = (lang==='en' ? '✗ Incorrect. ' : '✗ 錯誤。') + q.fb; } document.getElementById('btn-nextq').style.display = 'inline-block'; updateScoreBadge(); updateProgress(); } function nextQ() { quizIdx++; if(quizIdx >= quizData.length) showFinal(); else loadQuestion(); } function showFinal() { var pct = Math.round(quizScore/quizData.length*100); document.getElementById('quiz-q').textContent = lang==='en' ? 'Quiz Complete! You scored '+quizScore+'/'+quizData.length+' ('+pct+'%)' : '測驗完成!您的得分:'+quizScore+'/'+quizData.length+'('+pct+'%)'; document.getElementById('quiz-code').style.display='none'; document.getElementById('quiz-opts').innerHTML=''; document.getElementById('quiz-feedback').className='feedback-msg'; document.getElementById('btn-nextq').style.display='none'; updateProgress(); } function updateScoreBadge() { var t = lang==='en' ? 'Score: ' : '分數: '; document.getElementById('quiz-score-badge').textContent = t + quizScore; } function resetQuiz() { quizIdx=0; quizScore=0; answered=false; completedQ.clear(); loadQuestion(); updateProgress(); } function updateProgress() { var pct = completedQ.size / quizData.length * 100; document.getElementById('progress-fill').style.width = pct+'%'; document.getElementById('progress-pct').textContent = Math.round(pct)+'%'; } loadFlashcard(); loadQuestion();