Sound Blaster CT4170: історія, характеристики та можливості звукової карти

Sound Blaster CT4170 — цікава представниця пізнього покоління звукових карт Creative Sound Blaster для шини ISA. Вона належить до сімейства Sound Blaster 16, але вже істотно відрізняється від класичних SB16 початку 1990-х років.

CT4170 з’явилася приблизно у 1997 році та була орієнтована переважно на недорогі OEM-комп’ютери епохи Pentium і Pentium MMX. В її основі використовується чип Creative ViBRA 16XV CT2511.

Що таке Sound Blaster CT4170

CT4170 продавалася під назвами Sound Blaster 16 WavEffects та Sound Blaster 16 Value PnP. Це 16-бітна ISA Plug-and-Play звукова карта, розрахована на комп’ютери другої половини 1990-х років.

Основні можливості карти:

  • 16-бітний цифровий звук;
  • стереозвук;
  • відтворення аудіо до 44,1 кГц / 16 bit;
  • сумісність із Sound Blaster, Sound Blaster Pro та Sound Blaster 16;
  • AdLib-сумісний FM-синтез;
  • MIDI-інтерфейс;
  • Game/MIDI Port;
  • Line In;
  • Mic In;
  • Speaker/Line Out;
  • CD-ROM та AUX audio inputs;
  • 16-бітна ISA-шина;
  • ISA Plug-and-Play.

Для типового комп’ютера Pentium 100–233 MMX з Windows 95/98 та DOS-іграми це була цілком нормальна звукова карта свого часу.

Історія Sound Blaster 16

Щоб зрозуміти особливості CT4170, варто подивитися на розвиток сімейства Sound Blaster.

На початку 1990-х років Sound Blaster фактично став стандартом звукових карт для IBM PC-сумісних комп’ютерів. Поява Sound Blaster 16 принесла 16-бітний цифровий звук і зробила сімейство Creative ще популярнішим.

Ранні Sound Blaster 16 могли використовувати справжній Yamaha OPL3 для FM-синтезу. Саме OPL3 відповідав за характерну музику AdLib та Sound Blaster у багатьох DOS-іграх.

Однак до середини 1990-х років Creative почала активно здешевлювати конструкцію своїх звукових карт. У пізніших моделях замість Yamaha OPL3 почали використовувати власний CQM (Creative Quadratic Modulation).

CT4170 вже належить саме до цього періоду. Тому напис Sound Blaster 16 на карті є правильним з точки зору сумісності та позиціонування, але технічно це вже значно більш інтегрована та недорога конструкція.

CQM проти справжнього Yamaha OPL3

Для ретро-ігор це одна з найцікавіших особливостей CT4170.

CQM забезпечує програмну сумісність із OPL3 та AdLib, але технічно відрізняється від оригінального Yamaha OPL3. Через це музика в деяких іграх може звучати дещо інакше.

Залежно від конкретної гри можна почути:

  • інший тембр інструментів;
  • відмінності у FM-синтезі;
  • характерні високочастотні артефакти;
  • інше звучання окремих ефектів та інструментів.

Саме тому ентузіасти DOS-ретрогеймінгу часто віддають перевагу старішим Sound Blaster із реальним Yamaha OPL3.

Однак це не означає, що CT4170 погано звучить. Для таких ігор, як Doom, Duke Nukem 3D, Quake, Warcraft, Command & Conquer та багатьох інших, вона цілком придатна.

Що означає WavEffects

Назва WavEffects пов’язана з програмним синтезатором Creative. На відміну від AWE32 або AWE64, CT4170 не є повноцінною апаратною wavetable-картою з власною sample-пам’яттю.

Creative використовувала програмний WaveSynth, заснований на технології WaveGuide.

Тому між CT4170 та AWE32/AWE64 існує принципова різниця:

CT4170: SB16 + CQM FM + програмний WaveSynth.

AWE32/AWE64: апаратний sample-based синтез із власними можливостями відтворення семплів.

Особливості DMA та DOS-сумісності

У CT4170 є одна особливість, яка може мати значення під час використання старих DOS-ігор.

Карта не є повністю ідентичною класичному SB16 з точки зору реалізації DMA. Через це деякі старі програми та ігри, які очікують поведінку оригінального Sound Blaster 16, можуть вимагати додаткового налаштування.

Типова конфігурація Sound Blaster у DOS могла виглядати приблизно так:

A220 I5 D1 H5

де:

  • A220 — I/O address;
  • I5 — IRQ 5;
  • D1 — DMA;
  • H5 — high DMA.

Для CT4170 ситуація з high DMA дещо відрізняється від класичних SB16. Саме тому в окремих старих DOS-іграх можуть виникати проблеми або знадобитися специфічні налаштування.

Для якого комп’ютера призначалася CT4170

CT4170 дуже добре відображає типовий PC кінця 1990-х років.

Приблизно така конфігурація була цілком характерною для того часу:

Pentium / Pentium MMX → ISA → Windows 95/98 → Sound Blaster 16 → CD-ROM → активні колонки.

Особливо добре карта підходить для систем на базі:

  • Intel Pentium 100–166;
  • Pentium MMX 166–233;
  • ранніх Pentium II;
  • Windows 95;
  • Windows 98;
  • DOS 6.x / DOS 7.x.

Для 386 або 486 з чистим DOS вона вже не є настільки очевидним вибором. У таких системах старіший non-PnP Sound Blaster 16 або Sound Blaster Pro часто простіше налаштувати.

MIDI

CT4170 має MIDI/Game Port, але важливо розуміти його призначення.

MIDI-порт карти в першу чергу є MIDI-інтерфейсом, а не високоякісним внутрішнім MIDI-синтезатором рівня Roland.

Наприклад, до карти можна було підключити зовнішній MIDI-модуль на кшталт Roland Sound Canvas. У такому випадку CT4170 виступала інтерфейсом між комп’ютером і зовнішнім синтезатором.

Якщо ж потрібен якісний General MIDI без зовнішнього MIDI-модуля, AWE32, AWE64 або інші wavetable-рішення будуть значно цікавішими.

Якість звуку

Звучання CT4170 варто оцінювати окремо для цифрового аудіо та FM-музики.

Цифровий звук: цілком нормальний для свого часу — 16-бітний стереозвук із підтримкою частоти дискретизації до 44,1 кГц.

FM-музика: середня за мірками ретро-аудіо. CQM звучить інакше, ніж справжній Yamaha OPL3.

Шум та артефакти: як і багато недорогих Sound Blaster того покоління, CT4170 може мати фоновий шум, hiss та інші характерні для бюджетних карт артефакти. Водночас вона не є найгіршим представником сімейства ViBRA.

CT4170 серед інших Sound Blaster

Якщо дуже спрощено розташувати карти Creative тієї епохи за їхнім призначенням:

  • Sound Blaster Pro / ранні SB16 — старіші та простіші карти, особливо цікаві для DOS;
  • SB16 з Yamaha OPL3 — чудовий універсальний варіант для DOS;
  • CT4170 ViBRA 16XV — дешевший пізній SB16, особливо добре підходить для Windows 95/98 та DOS;
  • AWE32 — значно цікавіший варіант для апаратного MIDI та sample-based синтезу;
  • AWE64 — пізніша карта, добре пристосована до Windows 95/98 та General MIDI;
  • PCI Sound Blaster / Ensoniq — вже наступне покоління, яке не завжди так добре підходить для класичного DOS.

Чи варто використовувати CT4170 сьогодні?

CT4170 не є топовою Sound Blaster і не належить до найбільш цінних карт для колекціонерів. Проте це дуже характерна звукова карта кінця 1990-х років.

Для ретро-ПК вона може бути чудовим вибором, особливо якщо потрібно відтворити типовий комп’ютер 1997–1999 років.

Наприклад, конфігурація:

Pentium MMX + CT4170 + Windows 98 + Voodoo3

буде дуже автентичною для комп’ютера кінця 1990-х.

Якщо ж головна мета — створити максимально універсальний DOS-комп’ютер, який без проблем працюватиме з усіма старими іграми від AdLib до SB16, краще шукати Sound Blaster із реальним Yamaha OPL3.

Висновок

Sound Blaster CT4170 — це бюджетна, але цілком функціональна ISA-звукова карта другої половини 1990-х років. Вона являє собою пізній варіант Sound Blaster 16 на базі Creative ViBRA 16XV.

Її сильні сторони — хороша сумісність із великою кількістю DOS- та Windows-ігор, 16-бітний стереозвук, ISA Plug-and-Play та типова для епохи функціональність.

Головні компроміси — використання CQM замість справжнього Yamaha OPL3, бюджетна аналогова частина та деякі особливості сумісності з дуже старим DOS-софтом.

Тому CT4170 найкраще розглядати не як «погану дешеву Sound Blaster», а як характерний представник переходу від класичних DOS-звукових карт до масових Windows 95/98 PC.

Налаштування фаєрвола на Debian 13: закриваємо всі порти, залишаємо тільки SSH

Після встановлення чистого сервера Debian 13 одним із перших кроків має бути налаштування мережевої безпеки. Якщо доступ до сервера здійснюється виключно через SSH з використанням ключів, доцільно повністю закрити всі вхідні порти та залишити відкритим лише порт 22 для SSH.

У Debian 13 стандартним інструментом для фільтрації мережевого трафіку є nftables. Він входить до складу сучасних версій Linux і дозволяє гнучко налаштовувати правила фаєрвола.

Встановлення nftables

Оновіть список пакетів та встановіть nftables:

apt update
apt install nftables -y

Створення конфігурації фаєрвола

Відкрийте файл конфігурації:

nano /etc/nftables.conf

Вставте наступний вміст:

#!/usr/sbin/nft -f

flush ruleset

table inet filter {

    chain input {
        type filter hook input priority 0;
        policy drop;

        # localhost
        iif lo accept

        # вже встановлені з'єднання
        ct state established,related accept

        # SSH
        tcp dport 22 accept

        # ping (необов'язково)
        ip protocol icmp accept
        ip6 nexthdr icmpv6 accept
    }

    chain forward {
        type filter hook forward priority 0;
        policy drop;
    }

    chain output {
        type filter hook output priority 0;
        policy accept;
    }
}

Перевірка конфігурації

Перед застосуванням правил необхідно переконатися, що конфігурація не містить помилок:

nft -c -f /etc/nftables.conf

Якщо помилок не виявлено, можна активувати фаєрвол.

Запуск та автозавантаження

systemctl enable nftables
systemctl restart nftables

Перевірити завантажені правила можна командою:

nft list ruleset

Що роблять ці правила

  • Блокують усі вхідні підключення за замовчуванням.
  • Дозволяють локальний трафік через інтерфейс localhost.
  • Дозволяють вже встановлені та пов’язані з’єднання.
  • Відкривають лише порт 22 для SSH.
  • Дозволяють вихідні з’єднання сервера.
  • Блокують пересилання пакетів (forward).

Перевірка відкритих портів

Після налаштування фаєрвола рекомендується перевірити сервер з іншого пристрою:

nmap -Pn IP_СЕРВЕРА

У результаті повинен залишитися доступним лише SSH-порт:

22/tcp open ssh

Додатковий захист SSH

Якщо ви підключаєтесь до сервера лише з однієї статичної IP-адреси, можна дозволити доступ до SSH тільки з неї.

Замість правила:

tcp dport 22 accept

використовуйте:

ip saddr 203.0.113.55 tcp dport 22 accept

де 203.0.113.55 необхідно замінити на власну IP-адресу.

У такому випадку SSH буде доступний виключно з вказаної адреси, а всі інші спроби підключення будуть автоматично блокуватися.

Важливе застереження

Перед застосуванням нових правил рекомендується відкрити другу SSH-сесію та не закривати її до завершення перевірки. Це дозволить уникнути втрати доступу до сервера у випадку помилки в конфігурації фаєрвола.

Use To Find Hidden Website Pages

Most companies have an admin portal page, giving their staff access to basic admin controls for day-to-day operations. For a bank, an employee might need to transfer money to and from client accounts. Due to human error or negligence, there may be instances when these pages are not made private, allowing attackers to find hidden pages that show or give access to admin controls or sensitive data.

To begin, type the following command into the terminal to find potentially hidden pages on FakeBank’s website using (a command-line security application).

gobuster -u http://fakebank.thm -w wordlist.txt dir

The command will run and show you an output similar to this:

ubuntu@tryhackme:~/Desktop$ gobuster -u http://fakebank.thm -w wordlist.txt dir

=====================================================
Gobuster v2.0.1              OJ Reeves (@TheColonial)
=====================================================
[+] Mode         : dir
[+] Url/Domain   : http://fakebank.thm/
[+] Threads      : 10
[+] Wordlist     : wordlist.txt
[+] Status codes : 200,204,301,302,307,403
[+] Timeout      : 10s
=====================================================
2024/05/21 10:04:38 Starting gobuster
=====================================================
/images (Status: 301)
/bank-transfer (Status: 200)
=====================================================
2024/05/21 10:04:44 Finished
=====================================================

MikroTik Traffic Classification Using Mangle

This guide explains how to classify network traffic in
RouterOS running on
MikroTik routers using
Firewall Mangle.
The goal is to divide traffic into five logical directions:

  • LocalToGlobal – client traffic going to the Internet
  • GlobalToLocal – Internet traffic coming to clients
  • LocalToLocal – traffic between subscribers in the same network
  • LocalToMikrotik – traffic from subscribers to the router
  • MikrotikToLocal – traffic generated by the router to clients

This traffic model is very useful for Internet Service Providers and large
local networks because it allows:

  • bandwidth shaping using Queue Tree and PCQ
  • blocking client-to-client traffic
  • prioritizing management or service traffic
  • monitoring router-generated traffic

1. Network Concept

The following diagram represents the logical traffic directions:

Client → Internet      LocalToGlobal
Internet → Client      GlobalToLocal
Client → Client        LocalToLocal
Client → Router        LocalToMikrotik
Router → Client        MikrotikToLocal

To implement this architecture we will use two steps:

  1. Mark connections
  2. Mark packets based on those connections

2. Creating an Address List for Local Networks

First create an address list that contains all subscriber networks.
This list will be used to detect internal traffic.

/ip firewall address-list

add list=Local address=10.0.0.0/8
add list=Local address=172.16.0.0/12
add list=Local address=192.168.0.0/16

If your network uses a different addressing scheme, replace these ranges with
your actual subscriber networks.


3. Marking Connections

Connection marking is the first step.
Each new connection will be assigned a specific direction label.

LocalToGlobal (Client → Internet)

/ip firewall mangle
add chain=prerouting \
src-address-list=Local \
dst-address-list=!Local \
connection-mark=no-mark \
action=mark-connection \
new-connection-mark=LocalToGlobal_conn \
passthrough=yes

GlobalToLocal (Internet → Client)

add chain=prerouting \
src-address-list=!Local \
dst-address-list=Local \
connection-mark=no-mark \
action=mark-connection \
new-connection-mark=GlobalToLocal_conn \
passthrough=yes

LocalToLocal (Client → Client)

add chain=prerouting \
src-address-list=Local \
dst-address-list=Local \
connection-mark=no-mark \
action=mark-connection \
new-connection-mark=LocalToLocal_conn \
passthrough=yes

LocalToMikrotik (Client → Router)

add chain=input \
src-address-list=Local \
connection-mark=no-mark \
action=mark-connection \
new-connection-mark=LocalToMikrotik_conn \
passthrough=yes

MikrotikToLocal (Router → Client)

add chain=output \
dst-address-list=Local \
connection-mark=no-mark \
action=mark-connection \
new-connection-mark=MikrotikToLocal_conn \
passthrough=yes

4. Marking Packets

Once connections are marked, we classify packets belonging to those connections.
These packet marks are later used for traffic shaping and filtering.

Internet Upload Traffic

add chain=forward \
connection-mark=LocalToGlobal_conn \
action=mark-packet \
new-packet-mark=LocalToGlobal_pkt \
passthrough=no

Internet Download Traffic

add chain=forward \
connection-mark=GlobalToLocal_conn \
action=mark-packet \
new-packet-mark=GlobalToLocal_pkt \
passthrough=no

Local Network Traffic

add chain=forward \
connection-mark=LocalToLocal_conn \
action=mark-packet \
new-packet-mark=LocalToLocal_pkt \
passthrough=no

Traffic to Router

add chain=input \
connection-mark=LocalToMikrotik_conn \
action=mark-packet \
new-packet-mark=LocalToMikrotik_pkt \
passthrough=no

Router Generated Traffic

add chain=output \
connection-mark=MikrotikToLocal_conn \
action=mark-packet \
new-packet-mark=MikrotikToLocal_pkt \
passthrough=no

5. Practical Use Cases

Bandwidth Limiting

The marks LocalToGlobal_pkt and GlobalToLocal_pkt
can be used with Queue Tree to limit upload and download speeds per subscriber.

Blocking Client-to-Client Traffic

/ip firewall filter
add chain=forward connection-mark=LocalToLocal_conn action=drop

This prevents subscribers from accessing devices of other subscribers.

Allowing Router Access

Even when LocalToLocal traffic is blocked, clients can still reach the router
using the LocalToMikrotik direction for services like:

  • DNS
  • DHCP
  • WinBox
  • API
  • Monitoring

6. Important Notes

  • Disable FastTrack if Queue Tree shaping is used.
  • Ensure address lists correctly represent your network.
  • Keep connection marking rules above packet marking rules.
  • Test rules using /ip firewall mangle print stats.

Conclusion

This five-direction traffic classification model provides a flexible and
powerful framework for managing large subscriber networks on MikroTik routers.
By clearly separating Internet traffic, local traffic, and router traffic,
network administrators gain precise control over bandwidth usage, security,
and service prioritization.

How to Create a New WireGuard Client on a Linux Server (Debian/Ubuntu)

Wireguard is a modern, fast, and secure VPN solution.
This guide explains how to create a new WireGuard client on a Linux server
(Debian or Ubuntu) and connect it from a mobile device or desktop.


Prerequisites

  • A Linux server with WireGuard already installed
  • Root or sudo access
  • An existing WireGuard interface (e.g. wg0)

Example network used in this guide:

  • VPN subnet: 10.0.0.0/24
  • Server IP: 10.0.0.1
  • New client IP: 10.0.0.2

Step 1: Generate Client Keys

Navigate to the WireGuard configuration directory and set a secure file creation mask:

cd /etc/wireguard
umask 077

Generate the client private and public keys:

wg genkey | tee client1.key | wg pubkey > client1.pub

This creates:

  • client1.key — private key (keep secret)
  • client1.pub — public key

Step 2: Add the Client to the Server Configuration

Edit the server configuration file:

nano /etc/wireguard/wg0.conf

Add a new [Peer] section:

[Peer]
PublicKey = CLIENT1_PUBLIC_KEY
AllowedIPs = 10.0.0.2/32

Important: Each client must have a unique IP address.


Step 3: Apply the Configuration

Reload WireGuard without disconnecting active clients:

wg syncconf wg0 <(wg-quick strip wg0)

Or restart the interface:

systemctl restart wg-quick@wg0

Step 4: Create the Client Configuration File

Create a client configuration file:

nano client1.conf

Insert the following configuration:

[Interface]
PrivateKey = CLIENT1_PRIVATE_KEY
Address = 10.0.0.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = SERVER_PUBLIC_KEY
Endpoint = SERVER_IP:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25

Step 5: Generate a QR Code (Optional)

For mobile devices, you can generate a QR code:

apt install qrencode
qrencode -t ansiutf8 < client1.conf

Scan the QR code using the WireGuard mobile app to import the tunnel instantly.


Step 6: Verify the Connection

On the server, check the tunnel status:

wg show

If the client is connected, you will see:

  • Latest handshake timestamp
  • Data transfer statistics

Common Configuration Variants

Split Tunnel (VPN only for internal network)

AllowedIPs = 10.0.0.0/24

Full Tunnel (all traffic via VPN)

AllowedIPs = 0.0.0.0/0, ::/0

Security Notes

  • Never reuse client IP addresses
  • Protect private keys with file permissions (600)
  • Use PersistentKeepalive = 25 for mobile clients behind NAT

Conclusion

WireGuard makes VPN client management simple and secure.
By following this guide, you can safely add new clients,
generate configuration files, and connect from any modern device.

This setup works equally well for Android, iOS, Linux, Windows, and macOS clients.

How to create Telegram Bot in PHP

Creating a Telegram bot in PHP is a great way to automate tasks, provide customer support, send notifications, or build interactive services. Telegram offers a powerful and simple Bot API, and PHP makes it easy to handle web requests and responses.

In this step-by-step guide, you will learn how to create a Telegram bot using PHP, set up a webhook, and build a simple working example.

Step 1: Create a Telegram Bot with BotFather

Before writing any PHP code, you need to create your bot inside Telegram.

  1. Open Telegram and search for BotFather.
  2. Start a chat and send the command: /newbot
  3. Follow the instructions and choose a bot name and username.
  4. After creation, you will receive a Bot Token.

Save this token — you will need it to connect your PHP script to the Telegram Bot API.

Step 2: Set Up Your PHP Environment

To create a Telegram bot in PHP, you need:

  • A web server (Apache or Nginx)
  • PHP 7.4 or higher
  • HTTPS domain (Telegram requires SSL for webhooks)

Upload a PHP file (for example, bot.php) to your server.

Step 3: Basic Telegram Bot PHP Script

Below is a simple example of a Telegram bot written in PHP:

<?php
$token = "YOUR_BOT_TOKEN";
$apiURL = "https://api.telegram.org/bot" . $token . "/";


$content = file_get_contents("php://input");
$update = json_decode($content, true);


if (isset($update["message"])) {
$chatId = $update["message"]["chat"]["id"];
$text = $update["message"]["text"];


$response = "You said: " . $text;


file_get_contents($apiURL . "sendMessage?chat_id=" . $chatId . "&text=" . urlencode($response));
}
?>

Replace YOUR_BOT_TOKEN with the token provided by BotFather.

Step 4: Set Up a Webhook

Telegram needs to know where to send updates. You can set a webhook using this URL in your browser:

https://api.telegram.org/botYOUR_BOT_TOKEN/setWebhook?url=https://yourdomain.com/bot.php

If successful, Telegram will send messages directly to your PHP script whenever someone interacts with your bot.

Step 5: Testing Your Telegram PHP Bot

Now open your bot in Telegram and send a message. If everything is configured correctly, the bot will reply with:

You said: your message

Using cURL Instead of file_get_contents

For better performance and error handling, it is recommended to use cURL in PHP:

<?php
function sendMessage($chatId, $message, $token) {
$url = "https://api.telegram.org/bot$token/sendMessage";


$data = [
"chat_id" => $chatId,
"text" => $message
];


$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_exec($ch);
curl_close($ch);
}
?>

Best Practices for Telegram Bots in PHP

  • Always validate incoming data.
  • Use a framework for larger projects (Laravel, Symfony).
  • Store user data in a database (MySQL, PostgreSQL).
  • Use logging for debugging.
  • Secure your webhook endpoint.

Conclusion

Now you know how to create a Telegram bot in PHP using the Telegram Bot API and webhooks. With just a few lines of PHP code, you can build automated systems, chat assistants, and business tools.

Telegram bots are scalable, fast, and easy to maintain. As your project grows, you can expand your bot with inline keyboards, commands, databases, and third-party integrations.

Start building your PHP Telegram bot today and automate your workflow efficiently.

Як підключити USB 3G-модем Huawei E173 до Linux Mint

Huawei E173 — популярний USB 3G-модем, який добре підтримується Linux, але на сучасних версіях Linux Mint часто виникає ситуація, коли ModemManager не бачить модем, навіть якщо драйвери завантажені правильно.

У цій статті показано реальний робочий спосіб підключення Huawei E173 до Linux Mint, включно з діагностикою та стабільним рішенням через wvdial.


1. Перевірка визначення модема системою

Після підключення модема до USB перевіримо, чи бачить його система:

lsusb

Очікуваний результат:

Bus 001 Device 010: ID 12d1:1506 Huawei Technologies Co., Ltd. Modem/Networkcard

Важливо: ID 12d1:1506 означає, що модем уже в режимі модема (не CD-ROM), і usb_modeswitch не потрібен.


2. Перевірка портів ttyUSB

Модем Huawei E173 працює через послідовні порти. Перевіримо їх наявність:

ls /dev/ttyUSB*

Нормальний результат:

/dev/ttyUSB0
/dev/ttyUSB1
/dev/ttyUSB2

3. Перевірка драйверів ядра

Переконаємося, що драйвер option завантажений:

lsmod | grep option

Очікувано:

option      69632  1
usb_wwan    24576  1 option
usbserial   57344  4 usb_wwan,option

Це означає, що ядро Linux повністю готове до роботи з модемом.


4. Чому ModemManager не бачить Huawei E173

Команда:

mmcli -L

може повертати:

No modems were found

Це типова проблема на нових версіях Linux Mint. ModemManager орієнтований на LTE / QMI / MBIM і часто ігнорує старі 3G-модеми Huawei.

Рішення — використати перевірений класичний метод через wvdial.


5. Встановлення wvdial

sudo apt update
sudo apt install wvdial

6. Налаштування wvdial

Відкрий конфігураційний файл:

sudo nano /etc/wvdial.conf

Встав наступний конфіг:

[Dialer Defaults]
Init1 = ATZ
Init2 = ATQ0 V1 E1 S0=0 &C1 &D2
Init3 = AT+CGDCONT=1,"IP","internet"
Modem Type = Analog Modem
Phone = *99#
Username = user
Password = pass
Modem = /dev/ttyUSB0
Baud = 460800
Stupid Mode = 1
Auto DNS = 1
Carrier Check = no

APN для українських операторів

  • Kyivstarwww.kyivstar.net
  • Vodafone UAinternet
  • Lifecellinternet

APN змінюється в рядку Init3.


7. Підключення до інтернету

sudo wvdial

Успішне підключення виглядає так:

--> Dialing *99#
--> Starting pppd
--> local  IP address 10.x.x.x
--> remote IP address 10.x.x.x
--> primary   DNS address

Це означає, що з’єднання встановлено і інтернет працює.

Для відключення використовуйте Ctrl + C.


8. Якщо не підключається

Спробуйте змінити порт модема:

Modem = /dev/ttyUSB1

або

Modem = /dev/ttyUSB2

І повторіть команду sudo wvdial.


9. Перевірка мережевого інтерфейсу

Після підключення перевірте:

ip a

Має з’явитися інтерфейс ppp0.


Як у PDO перейти з MySQL на PostgreSQL

PDO (PHP Data Objects) дозволяє змінити базу даних з MySQL на PostgreSQL без переписування PHP-коду, якщо код написаний правильно. Однак потрібно розуміти, що саме змінюється, а що — ні.


1. Головне правило

PDO прибирає залежність від драйвера БД, але не від SQL-діалекту.

  • ✔ PHP-код зазвичай не змінюється
  • ✔ змінюється DSN підключення
  • ❌ SQL-запити та структура БД можуть потребувати адаптації

2. Заміна DSN (обовʼязково)

Було: MySQL

$pdo = new PDO(
    "mysql:host=localhost;dbname=test_db;charset=utf8mb4",
    "db_user",
    "db_pass",
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    ]
);

Стало: PostgreSQL

$pdo = new PDO(
    "pgsql:host=localhost;port=5432;dbname=test_db",
    "db_user",
    "db_pass",
    [
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
    ]
);

Весь інший PHP-код залишається без змін.


3. PDO-код, який працює і в MySQL, і в PostgreSQL

$stmt = $pdo->prepare(
    "SELECT id, name FROM users WHERE active = :active"
);

$stmt->execute([
    'active' => true
]);

$rows = $stmt->fetchAll();

4. Що ламається при переході (і як виправити)

LIMIT offset, count

MySQL:

LIMIT 10, 20

PostgreSQL:

LIMIT 20 OFFSET 10

Універсальний варіант:

LIMIT :limit OFFSET :offset

AUTO_INCREMENT

MySQL:

id INT AUTO_INCREMENT

PostgreSQL:

id SERIAL
-- або
id INT GENERATED ALWAYS AS IDENTITY

PHP-код не змінюється, якщо використовується lastInsertId().


INSERT IGNORE

MySQL:

INSERT IGNORE INTO users (...)

PostgreSQL:

INSERT INTO users (...)
ON CONFLICT DO NOTHING

ON DUPLICATE KEY UPDATE

MySQL:

ON DUPLICATE KEY UPDATE name = VALUES(name)

PostgreSQL:

ON CONFLICT (email)
DO UPDATE SET name = EXCLUDED.name

IF()

MySQL:

IF(active = 1, 'yes', 'no')

PostgreSQL:

CASE WHEN active THEN 'yes' ELSE 'no' END

5. Типи даних, які потрібно змінити

MySQL PostgreSQL
TINYINT(1) BOOLEAN
DATETIME TIMESTAMP
LONGTEXT TEXT
DOUBLE DOUBLE PRECISION

6. JSON — різний синтаксис

MySQL:

JSON_EXTRACT(data, '$.name')

PostgreSQL:

data->>'name'

7. Рекомендовані налаштування PDO

$options = [
    PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
    PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
    PDO::ATTR_EMULATE_PREPARES   => false
];

8. Коли можна змінити БД без змін PHP

  • ✔ використовується PDO
  • ✔ немає MySQL-специфічного SQL
  • ✔ відсутні FULLTEXT, ENUM, REPLACE INTO

9. Висновок

Перехід з MySQL на PostgreSQL у PDO — це перш за все:

  • 🔹 заміна DSN
  • 🔹 адаптація SQL-запитів
  • 🔹 міграція структури БД

PDO значно спрощує міграцію, але не є повною абстракцією від SQL.

Рекомендація: завжди пишіть портований SQL, щоб у майбутньому легко змінювати СУБД.

Як використовувати цикл for з PDO SELECT у PHP

PDO не дозволяє напряму перебирати результат запиту циклом for. Але цикл for можна використовувати, якщо попередньо отримати дані у вигляді масиву.


1. Основна ідея

Алгоритм такий:

  1. Виконати SELECT через PDO
  2. Отримати всі рядки методом fetchAll()
  3. Перебрати масив циклом for

2. Простий приклад SELECT + for

$stmt = $pdo->query(
    "SELECT id, name, email FROM users"
);

$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);

for ($i = 0; $i < count($rows); $i++) {
    echo $rows[$i]['id'] . ' - ';
    echo $rows[$i]['name'] . ' - ';
    echo $rows[$i]['email'] . '<br>';
}

3. Оптимізований варіант (рекомендовано)

Щоб не викликати count() на кожній ітерації, краще зберегти кількість елементів у змінну:

$total = count($rows);

for ($i = 0; $i < $total; $i++) {
    echo $rows[$i]['name'] . '<br>';
}

4. SELECT з параметрами + for

$stmt = $pdo->prepare(
    "SELECT id, name FROM users WHERE active = :active"
);

$stmt->execute([
    'active' => 1
]);

$users = $stmt->fetchAll(PDO::FETCH_ASSOC);

for ($i = 0, $c = count($users); $i < $c; $i++) {
    echo $users[$i]['id'] . ' - ';
    echo $users[$i]['name'] . '<br>';
}

5. Поширена помилка (НЕПРАВИЛЬНО)

for ($i = 0; $row = $stmt->fetch(); $i++) {
    // ❌ так робити не можна
}

Метод fetch() повертає false, а цикл for не призначений для такої логіки.


6. Кращі альтернативи циклу for

while (рекомендовано для великих вибірок)

while ($row = $stmt->fetch()) {
    echo $row['name'] . '<br>';
}

foreach (найчистіший код)

foreach ($users as $row) {
    echo $row['name'] . '<br>';
}

7. Коли варто використовувати for

  • ✔ Потрібен індекс елемента
  • ✔ Дані вже у масиві
  • ✔ Є логіка, залежна від позиції

Коли НЕ варто

  • ❌ Для великих SELECT-запитів
  • ❌ Коли не потрібен індекс

8. Висновок

Цикл for можна використовувати з PDO лише після fetchAll(). У більшості випадків foreach або while будуть простішими та ефективнішими.

Рекомендація: використовуйте for тільки тоді, коли це дійсно виправдано.

Повний гайд: як користуватися PDO в PHP

PDO (PHP Data Objects) — це сучасний, безпечний та універсальний спосіб роботи з базами даних у PHP. PDO підтримує MySQL, PostgreSQL, SQLite та інші СУБД і дозволяє писати портований код без прив’язки до конкретної бази.

У цій статті ви навчитеся користуватися PDO на практиці: від підключення до бази даних до виконання складних запитів і транзакцій.


1. Чому варто використовувати PDO

  • ✔ Захист від SQL-інʼєкцій
  • ✔ Prepared statements
  • ✔ Єдиний API для різних СУБД
  • ✔ Підтримка транзакцій
  • ✔ Зручна обробка помилок

2. Підключення до бази даних через PDO

<?php
$dsn  = "mysql:host=localhost;dbname=test_db;charset=utf8mb4";
$user = "db_user";
$pass = "db_password";

try {
    $pdo = new PDO($dsn, $user, $pass, [
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES   => false,
    ]);
} catch (PDOException $e) {
    die("Помилка підключення: " . $e->getMessage());
}

3. SELECT-запити

Простий SELECT

$stmt = $pdo->query("SELECT * FROM users");
$users = $stmt->fetchAll();

SELECT з параметрами (prepared statement)

$stmt = $pdo->prepare(
    "SELECT * FROM users WHERE email = :email"
);

$stmt->execute([
    'email' => '[email protected]'
]);

$user = $stmt->fetch();

4. INSERT, UPDATE, DELETE

INSERT

$stmt = $pdo->prepare(
    "INSERT INTO users (name, email)
     VALUES (:name, :email)"
);

$stmt->execute([
    'name'  => 'Ivan',
    'email' => '[email protected]'
]);

$lastId = $pdo->lastInsertId();

UPDATE

$stmt = $pdo->prepare(
    "UPDATE users SET name = :name WHERE id = :id"
);

$stmt->execute([
    'name' => 'Petro',
    'id'   => 5
]);

DELETE

$stmt = $pdo->prepare(
    "DELETE FROM users WHERE id = :id"
);

$stmt->execute([
    'id' => 10
]);

5. Плейсхолдери в PDO

Іменовані

WHERE id = :id

Позиційні

WHERE id = ?
$stmt->execute([5]);

6. Типи даних та bindValue

Для числових значень, LIMIT та OFFSET рекомендується явно вказувати тип:

$stmt = $pdo->prepare(
    "SELECT * FROM users
     WHERE active = :active
     LIMIT :limit OFFSET :offset"
);

$stmt->bindValue(':active', true, PDO::PARAM_BOOL);
$stmt->bindValue(':limit', 20, PDO::PARAM_INT);
$stmt->bindValue(':offset', 0, PDO::PARAM_INT);

$stmt->execute();

7. Отримання результатів

  • fetch() — один рядок
  • fetchAll() — всі рядки
  • rowCount() — не рекомендовано для SELECT

8. Транзакції

try {
    $pdo->beginTransaction();

    $pdo->exec(
        "UPDATE accounts
         SET balance = balance - 100
         WHERE id = 1"
    );

    $pdo->exec(
        "UPDATE accounts
         SET balance = balance + 100
         WHERE id = 2"
    );

    $pdo->commit();
} catch (Exception $e) {
    $pdo->rollBack();
    echo "Помилка транзакції";
}

9. Обробка помилок

try {
    $pdo->query("SELECT * FROM unknown_table");
} catch (PDOException $e) {
    echo $e->getMessage();
}

10. Типові помилки при роботі з PDO

  • ❌ Конкатенація змінних у SQL
  • ❌ Відсутність prepared statements
  • ❌ ATTR_EMULATE_PREPARES = true
  • ❌ rowCount() для SELECT

11. PDO у WordPress

Хоча WordPress використовує $wpdb, PDO можна застосовувати:

  • у власних плагінах
  • у REST API
  • у CLI-скриптах

12. Висновок

PDO — це стандарт для сучасного PHP. Використання prepared statements, транзакцій та портованого SQL робить код безпечним, масштабованим і готовим до майбутніх змін.

Рекомендація: завжди використовуйте PDO у нових PHP-проєктах.