Showing posts with label PHP. Show all posts
Showing posts with label PHP. Show all posts

Wednesday, 9 April 2025

Use Redis Pub/Sub to check user online compare to not use

Khi sử dụng Redis Pub/Sub, hệ thống vẫn phải bắn sự kiện qua Private Channel của Reverb để gửi đến client. Tuy nhiên, Redis Pub/Sub mang lại hiệu suất cao hơn so với cách không dùng nó, và mình sẽ giải thích chi tiết tại sao, đồng thời làm rõ sự khác biệt giữa hai cách.


1. Cách hoạt động khi dùng Redis Pub/Sub

Quy trình

  1. User thay đổi trạng thái (ví dụ: User 500 offline):
    • Server gọi UserStatusService::setOffline(500).
    • Redis xóa trạng thái (user:500:status) và publish sự kiện đến các kênh riêng của bạn bè (ví dụ: user:1:status, user:2:status).
  2. Worker Redis Subscriber:
    • Lắng nghe tất cả kênh user:*:status.
    • Khi nhận message từ Redis (ví dụ: user:1:status), worker broadcast sự kiện qua Reverb đến kênh private-user.1.
  3. Client:
    • Mỗi user lắng nghe kênh riêng của mình (ví dụ: private-user.1) qua Laravel Echo.
    • Nhận sự kiện và cập nhật UI.

Tại sao vẫn cần Private Channel?

  • Redis Pub/Sub không giao tiếp trực tiếp với client: Redis chỉ là hệ thống lưu trữ và truyền tin nội bộ giữa các server/process. Nó không thể gửi dữ liệu trực tiếp đến browser qua WebSocket.
  • Reverb (WebSocket): Đảm nhận việc gửi sự kiện từ server đến client qua kết nối WebSocket. Private Channel giúp gửi đúng đối tượng (chỉ bạn bè nhận được thông báo).
  • Kết hợp: Redis Pub/Sub truyền tin nhanh trong backend, Reverb chuyển tiếp tin đó đến client qua Private Channel.

2. So sánh với cách không dùng Redis Pub/Sub

Không dùng Redis Pub/Sub

  1. Quy trình:
    • User 500 offline → Server truy vấn database để lấy danh sách bạn bè (User 1, User 2, User 3).
    • Server broadcast sự kiện qua Reverb đến các kênh private-user.1, private-user.2, private-user.3 bằng cách gọi event() trực tiếp trong PHP:
      php
      foreach ($friendIds as $friendId) { event(new UserStatusChanged($userId, 'offline', $friendId)); }
  2. Nhược điểm:
    • Truy vấn database: Mỗi lần user thay đổi trạng thái, phải query bảng friends (hoặc tương tự) để lấy danh sách bạn bè → chậm, đặc biệt nếu danh sách lớn (1000 bạn).
    • Tải xử lý: PHP phải thực hiện vòng lặp và gửi từng event trong cùng một request → tốn CPU và thời gian.

Dùng Redis Pub/Sub

  1. Quy trình:
    • User 500 offline → Server lấy danh sách bạn bè từ Redis (nếu đã cache) hoặc database, rồi publish đến các kênh Redis (user:1:status, user:2:status).
    • Worker Redis subscribe nhận message và broadcast qua Reverb.
  2. Ưu điểm:
    • Lấy dữ liệu nhanh hơn: Nếu danh sách bạn bè được cache trong Redis (ví dụ: user:500:friends), truy vấn từ Redis (in-memory) nhanh hơn rất nhiều so với database (disk-based).
    • Xử lý bất đồng bộ: Redis Pub/Sub và worker chạy độc lập, không chặn request chính của PHP → giảm tải server.
    • Tốc độ publish: Redis xử lý hàng nghìn message/giây, nhẹ hơn việc PHP gọi event() trong vòng lặp.

3. Tại sao Redis Pub/Sub nhanh hơn?

Lý do chính

  1. Truy vấn nhanh từ Redis:
    • Không dùng Redis Pub/Sub: Mỗi lần broadcast cần query database để lấy danh sách bạn bè → tốn thời gian (vài ms đến hàng chục ms tùy kích thước bảng).
    • Dùng Redis Pub/Sub: Nếu danh sách bạn bè đã cache trong Redis (ví dụ: user:500:friends dưới dạng Set), truy xuất chỉ mất <1ms vì Redis là in-memory.
  2. Bất đồng bộ:
    • Không dùng Redis: PHP xử lý toàn bộ logic (query + broadcast) trong một request → đồng bộ, dễ gây bottleneck.
    • Dùng Redis Pub/Sub: Publish là hành động tức thời, worker xử lý song song → không chặn request chính.
  3. Hiệu suất Pub/Sub:
    • Redis Pub/Sub được thiết kế để truyền tin nhanh, không cần lưu trữ lâu dài, phù hợp cho sự kiện realtime.
    • Gửi 1000 message qua Redis Pub/Sub nhanh hơn gọi 1000 lần event() trong PHP.

Minh họa thời gian

  • Không Redis: Query database (10ms) + vòng lặp 1000 bạn (50ms) = ~60ms cho 1 sự kiện.
  • Có Redis: Cache Redis (1ms) + publish 1000 kênh (5ms) = ~6ms, cộng với worker xử lý bất đồng bộ.

4. Ví dụ cụ thể

Không dùng Redis Pub/Sub

php
public static function setOffline($userId) { Redis::del("user:$userId:status"); $friendIds = User::find($userId)->friends()->pluck('id')->toArray(); // Query database foreach ($friendIds as $friendId) { event(new \App\Events\UserStatusChanged($userId, 'offline', $friendId)); // Gửi từng event } }
  • Chậm vì: Query database + vòng lặp tuần tự.

Dùng Redis Pub/Sub

php
public static function setOffline($userId) { Redis::del("user:$userId:status"); $friendIds = Redis::smembers("user:$userId:friends"); // Lấy từ Redis if (!$friendIds) { $friendIds = User::find($userId)->friends()->pluck('id')->toArray(); Redis::sadd("user:$userId:friends", $friendIds); // Cache lần đầu } foreach ($friendIds as $friendId) { Redis::publish("user:$friendId:status", json_encode(['userId' => $userId, 'status' => 'offline'])); } }
  • Nhanh vì: Lấy từ Redis (nếu đã cache) + publish bất đồng bộ.

Worker Redis

php
public function handle() { Redis::psubscribe(['user:*:status'], function ($message, $channel) { $data = json_decode($message, true); $friendId = explode(':', $channel)[1]; broadcast(new \App\Events\UserStatusChanged($data['userId'], $data['status'], $friendId)); }); }

5. Kết luận

  • Vẫn cần Private Channel: Redis Pub/Sub chỉ thay thế bước gửi sự kiện nội bộ trong backend. Reverb dùng Private Channel để gửi từ server đến client.
  • Nhanh hơn vì:
    1. Truy xuất danh sách bạn bè từ Redis thay vì database.
    2. Publish qua Redis bất đồng bộ, nhẹ hơn gọi event() tuần tự trong PHP.
  • Hiệu quả: Với 1000 user, cách này giảm tải server và tăng tốc độ xử lý từ vài chục ms xuống vài ms.

Thank you

Monday, 31 March 2025

10 Câu Hỏi Nâng Cao Về MySQL & PHP

 10 Câu Hỏi Nâng Cao Về MySQL

  1. Trong một hệ thống có hàng triệu bản ghi, làm thế nào để bạn tối ưu hóa hiệu suất của các truy vấn phức tạp liên quan đến nhiều bảng, đặc biệt khi sử dụng các phép JOIN và GROUP BY?

(Kiểm tra khả năng tối ưu hóa truy vấn ở quy mô lớn.)

  1. Bạn đã từng làm việc với MySQL partitioning chưa? Hãy mô tả một tình huống cụ thể mà bạn đã sử dụng partitioning để cải thiện hiệu suất, và kết quả ra sao?

(Tập trung vào kỹ thuật nâng cao để quản lý dữ liệu lớn.)

  1. Khi thiết kế một hệ thống cần đảm bảo tính sẵn sàng cao (high availability) với MySQL, bạn sẽ triển khai kiến trúc nào, và làm thế nào để xử lý các vấn đề như failover và đồng bộ dữ liệu?

(Kiểm tra kinh nghiệm với kiến trúc hệ thống và HA.)

  1. Làm thế nào để bạn xử lý các vấn đề về deadlock trong MySQL khi nhiều giao dịch đồng thời truy cập cùng một tập dữ liệu? Hãy đưa ra một ví dụ cụ thể.

(Tập trung vào quản lý giao dịch và giải quyết xung đột.)

  1. MySQL có hỗ trợ full-text search. Bạn đã từng sử dụng tính năng này chưa? Nếu có, hãy mô tả cách bạn triển khai và những hạn chế bạn gặp phải.

(Kiểm tra kinh nghiệm với tính năng nâng cao của MySQL.)

  1. Khi làm việc với MySQL trong một ứng dụng Laravel, làm thế nào để bạn xử lý các truy vấn phức tạp mà Eloquent không thể đáp ứng một cách hiệu quả?

(Kết hợp kinh nghiệm Laravel với MySQL nâng cao.)

  1. Bạn đã từng sử dụng EXPLAIN ANALYZE trong MySQL chưa? Hãy giải thích cách bạn sử dụng nó để tối ưu hóa một truy vấn cụ thể trong một dự án.

(Tập trung vào phân tích và tối ưu hóa truy vấn.)

  1. Làm thế nào để bạn triển khai một hệ thống sao lưu (backup) và khôi phục (restore) cho MySQL trong môi trường production, và bạn xử lý các vấn đề về dữ liệu lớn như thế nào?

(Kiểm tra kinh nghiệm DevOps và quản lý cơ sở dữ liệu.)

  1. MySQL có hỗ trợ các tính năng như CTE (Common Table Expressions) và window functions. Bạn đã từng sử dụng chúng chưa? Hãy đưa ra một ví dụ cụ thể.

(Tập trung vào các tính năng SQL nâng cao.)

  1. Khi làm việc với một hệ thống phân tán, làm thế nào để bạn đảm bảo tính nhất quán dữ liệu (data consistency) giữa các node MySQL, và bạn đã gặp phải thách thức gì?

(Kiểm tra kinh nghiệm với hệ thống phân tán và đồng bộ dữ liệu.)


10 Câu Hỏi Nâng Cao Về PHP

  1. Trong một ứng dụng Laravel có lưu lượng truy cập cao, làm thế nào để bạn triển khai một hệ thống hàng đợi (queue) để xử lý các tác vụ nặng như gửi email hoặc xử lý dữ liệu lớn? Hãy mô tả chi tiết.

(Tập trung vào xử lý tác vụ bất đồng bộ và tối ưu hóa hiệu suất.)

  1. Bạn đã từng sử dụng PHP để xây dựng một hệ thống microservices chưa? Nếu có, hãy mô tả cách bạn thiết kế và những thách thức bạn gặp phải.

(Kiểm tra kinh nghiệm với kiến trúc microservices.)

  1. Làm thế nào để bạn triển khai một hệ thống caching phân tán (distributed caching) trong Laravel, và bạn đã sử dụng nó để giải quyết vấn đề gì trong một dự án?

(Tập trung vào tối ưu hóa hiệu suất với caching.)

  1. Khi làm việc với Laravel, làm thế nào để bạn xử lý các vấn đề về hiệu suất khi ứng dụng phải xử lý hàng nghìn request mỗi giây? Hãy đưa ra ví dụ cụ thể.

(Kiểm tra kinh nghiệm tối ưu hóa hiệu suất ở quy mô lớn.)

  1. Bạn đã từng sử dụng PHP để triển khai một hệ thống event-driven chưa? Hãy mô tả cách bạn thiết kế và những công cụ bạn sử dụng.

(Tập trung vào kiến trúc event-driven và xử lý sự kiện.)

  1. Làm thế nào để bạn triển khai một hệ thống xác thực (authentication) tùy chỉnh trong Laravel cho một ứng dụng doanh nghiệp, và bạn xử lý các yêu cầu bảo mật phức tạp như thế nào?

(Kiểm tra kinh nghiệm với bảo mật và tùy chỉnh Laravel.)

  1. Bạn đã từng làm việc với PHP để xử lý các tác vụ đồng thời (concurrency) chưa? Hãy mô tả cách bạn sử dụng các công cụ như Swoole hoặc các kỹ thuật khác.

(Tập trung vào xử lý đồng thời trong PHP.)

  1. Khi làm việc với một ứng dụng Laravel lớn, làm thế nào để bạn quản lý các dependency và đảm bảo mã có thể kiểm thử (testable)? Hãy đưa ra ví dụ cụ thể.

(Kiểm tra kiến thức về thiết kế phần mềm và kiểm thử.)

  1. Bạn đã từng sử dụng PHP để xây dựng một hệ thống xử lý dữ liệu thời gian thực (real-time) chưa? Nếu có, hãy mô tả cách bạn triển khai và những thách thức bạn gặp phải.

(Tập trung vào ứng dụng thời gian thực và WebSocket.)

  1. Làm thế nào để bạn triển khai một hệ thống logging và monitoring trong một ứng dụng Laravel để phát hiện và xử lý lỗi trong môi trường production?

(Kiểm tra kinh nghiệm DevOps và quản lý ứng dụng.)


Thursday, 9 January 2025

Containerization of PHP and Nginx

Containerization of PHP and Nginx [2025]

Containerizing PHP and Nginx involves creating Docker containers for each service and configuring them to work together seamlessly. This approach ensures consistency across different environments, simplifies deployment, and enhances scalability. Below are the detailed steps to create a basic Docker configuration for PHP and Nginx, based on a simple PHP application.

Table of Contents

  1. Create the Project Structure
  2. Create a PHP Application
  3. Configure Nginx
  4. Create Dockerfile for PHP
  5. Create Dockerfile for Nginx
  6. Create docker-compose.yml
  7. Build and Run the Containers
  8. Verify the Setup
  9. Additional Considerations
  10. Conclusion

1. Create the Project Structure

Start by setting up your project with the following structure:

project
├── index.php
├── nginx
│   └── nginx.conf
├── Dockerfile
├── Dockerfile-nginx
└── docker-compose.yml

This structure organizes your PHP application, Nginx configuration, Dockerfiles, and Docker Compose file in a clear and maintainable manner.

2. Create a PHP Application

Create a simple PHP application to serve as the basis for containerization. In the root of your project (./index.php), add the following code:

<?php
  echo "Hello!";
?>

This basic script will help you verify that your container setup is working correctly.

3. Configure Nginx

Create an Nginx configuration file in nginx/nginx.conf with the following content:

server {
    listen 80;
    server_name localhost;

    root /var/www/html;
    index index.php index.html;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass php:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME /var/www/html$fastcgi_script_name;
    }
}

Explanation:

  • listen 80;: Nginx listens on port 80 for incoming HTTP requests.
  • server_name localhost;: Defines the server name.
  • root /var/www/html;: Sets the root directory for the server.
  • index index.php index.html;: Specifies the index files.
  • location /: Handles requests to the root URL, trying to serve the requested file or returning a 404 error if not found.
  • location ~ .php$: Processes PHP files using PHP-FPM running in the php container on port 9000.

4. Create Dockerfile for PHP

Create a Dockerfile in the root of your project to set up the PHP environment:

# Use the official PHP image with PHP-FPM
FROM php:8.1-fpm

# Set working directory
WORKDIR /var/www/html

# Install necessary PHP extensions
RUN docker-php-ext-install mysqli pdo pdo_mysql

# Copy application files
COPY . /var/www/html

# Set permissions
RUN chown -R www-data:www-data /var/www/html

# Expose port 9000
EXPOSE 9000

# Start PHP-FPM server
CMD ["php-fpm"]

Explanation:

  • FROM php:8.1-fpm: Uses the official PHP image with PHP-FPM.
  • WORKDIR /var/www/html: Sets the working directory inside the container.
  • RUN docker-php-ext-install mysqli pdo pdo_mysql: Installs necessary PHP extensions.
  • COPY . /var/www/html: Copies the application code into the container.
  • RUN chown -R www-data:www-data /var/www/html: Sets appropriate permissions.
  • EXPOSE 9000: Exposes port 9000 for communication with Nginx.
  • CMD ["php-fpm"]: Starts the PHP-FPM server.

5. Create Dockerfile for Nginx

Create a Dockerfile-nginx in the nginx directory to set up the Nginx environment:

# Use the official Nginx image
FROM nginx:latest

# Remove the default Nginx configuration
RUN rm /etc/nginx/conf.d/default.conf

# Copy the custom Nginx configuration
COPY nginx.conf /etc/nginx/conf.d

# Copy application files to serve static content if needed
COPY ../ /var/www/html

# Expose port 80
EXPOSE 80

# Start Nginx
CMD ["nginx", "-g", "daemon off;"]

Explanation:

  • FROM nginx:latest: Uses the latest official Nginx image.
  • RUN rm /etc/nginx/conf.d/default.conf: Removes the default Nginx configuration.
  • COPY nginx.conf /etc/nginx/conf.d: Copies your custom Nginx configuration.
  • COPY ../ /var/www/html: Copies application files for serving static content.
  • EXPOSE 80: Exposes port 80 for HTTP traffic.
  • CMD ["nginx", "-g", "daemon off;"]: Starts Nginx in the foreground.

6. Create docker-compose.yml

Create a docker-compose.yml file in the root of your project to orchestrate the PHP and Nginx containers:

version: '3.8'

services:
  php:
    build:
      context: .
      dockerfile: Dockerfile
    volumes:
      - .:/var/www/html
    networks:
      - app-network

  nginx:
    build:
      context: ./nginx
      dockerfile: Dockerfile-nginx
    ports:
      - "80:80"
    depends_on:
      - php
    volumes:
      - .:/var/www/html
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

Explanation:

  • version: '3.8': Specifies the Docker Compose version.
  • services: Defines the services (php and nginx).
    • php:
      • build: Builds the PHP container using the specified Dockerfile.
      • volumes: Mounts the current directory to /var/www/html inside the container.
      • networks: Connects to the app-network.
    • nginx:
      • build: Builds the Nginx container using the specified Dockerfile.
      • ports: Maps port 80 of the host to port 80 of the container.
      • depends_on: Ensures Nginx starts after PHP.
      • volumes: Mounts the current directory to /var/www/html inside the container.
      • networks: Connects to the app-network.
  • networks:
    • app-network: Defines a bridge network for inter-service communication.

7. Build and Run the Containers

Navigate to the root of your project in the terminal and execute the following command to build and start the containers:

docker-compose up -d --build
  • -d: Runs the containers in detached mode.
  • --build: Forces a rebuild of the Docker images.

Expected Output:

Creating network "project_app-network" with the default driver
Building php
Step 1/7 : FROM php:8.1-fpm
...
Successfully built abc123def456
Successfully tagged project_php:latest
Building nginx
Step 1/5 : FROM nginx:latest
...
Successfully built ghi789jkl012
Successfully tagged project_nginx:latest
Creating project_php_1    ... done
Creating project_nginx_1 ... done

8. Verify the Setup

After the containers are up and running, open your web browser and navigate to http://localhost. You should see the message:

Hello!

This confirms that Nginx is correctly serving the PHP application through the Docker containers.

Troubleshooting Tips

  • Port Conflicts: Ensure that port 80 is not being used by another service on your host machine.

  • Container Logs: If you encounter issues, check the logs using:

    docker-compose logs
    
  • Container Status: Verify that all containers are running using:

    docker-compose ps
    

9. Additional Considerations

While the above setup provides a basic containerization of PHP and Nginx, consider the following enhancements for more complex applications:

Environment Variables

Manage configuration settings using environment variables. You can define them in the docker-compose.yml file under each service or use a .env file for better security and flexibility.

services:
  php:
    environment:
      - APP_ENV=production
      - DB_HOST=db
  nginx:
    environment:
      - NGINX_HOST=localhost

Database Integration

If your PHP application requires a database, add another service (e.g., MySQL or PostgreSQL) to the docker-compose.yml and configure PHP to connect to it.

services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpassword
      MYSQL_DATABASE: app_db
      MYSQL_USER: app_user
      MYSQL_PASSWORD: app_password
    volumes:
      - db_data:/var/lib/mysql
    networks:
      - app-network

volumes:
  db_data:

Update the php service to include the database connection details.

Persistent Storage

Ensure that any data you want to persist (like database files) is stored in Docker volumes to prevent data loss when containers are recreated.

Scaling Services

Docker Compose allows you to scale services. For example, you can run multiple instances of the PHP service to handle increased load:

docker-compose up --scale php=3 -d

Security

  • Update Docker Images: Always keep your Docker images updated to include the latest security patches.

  • Multi-Stage Builds: Use multi-stage builds to minimize the image size and reduce the attack surface.

    FROM node:14 AS build
    WORKDIR /app
    COPY . .
    RUN npm install && npm run build
    
    FROM nginx:alpine
    COPY --from=build /app/build /usr/share/nginx/html
    
  • User Permissions: Run containers with non-root users where possible to enhance security.

Logging and Monitoring

Implement logging and monitoring solutions to track the performance and health of your containers. Tools like Prometheus, Grafana, and ELK Stack can be integrated for comprehensive monitoring.

10. Conclusion

Containerizing PHP and Nginx using Docker simplifies the deployment process, ensures consistency across different environments, and enhances scalability. By following the steps outlined above, you can set up a robust environment for your PHP applications, making development and deployment more efficient and manageable.

Embracing containerization not only streamlines your workflow but also positions your applications for better performance and reliability in production environments. As you grow your applications, consider integrating more advanced Docker features and orchestration tools like Kubernetes to further optimize your infrastructure.


Happy Coding!

Feel free to follow me for more insights on containerization, Docker, and web development best practices.

Monday, 2 December 2024

Late static binding and early binding in PHP

Late static binding and early binding are concepts in PHP that describe how methods or properties are resolved when a class hierarchy is involved. The key difference lies in when the resolution occurs and which class context is used.


Early Binding (self)

  • Definition: Early binding resolves the method or property to the class in which it is defined, regardless of the class from which it is called.
  • Behavior:
    • Uses self to reference the class where the code is written.
    • The binding happens at compile time.
    • Does not respect polymorphism in class hierarchies.

Example:

class ParentClass { public static function who() { return "ParentClass"; } public static function callWho() { return self::who(); // Early binding to ParentClass::who() } } class ChildClass extends ParentClass { public static function who() { return "ChildClass"; } } echo ParentClass::callWho(); // Output: ParentClass echo ChildClass::callWho(); // Output: ParentClass

Explanation:

  • self::who() in callWho() binds to the method who() in ParentClass because self is resolved at compile time.
  • Even when ChildClass calls callWho(), it does not use ChildClass::who().

Late Static Binding (static)

  • Definition: Late static binding resolves the method or property to the class that is actually calling the method (runtime class context).
  • Behavior:
    • Uses static to reference the calling class.
    • The binding happens at runtime.
    • Respects polymorphism in class hierarchies.

Example:

class ParentClass { public static function who() { return "ParentClass"; } public static function callWho() { return static::who(); // Late static binding } } class ChildClass extends ParentClass { public static function who() { return "ChildClass"; } } echo ParentClass::callWho(); // Output: ParentClass echo ChildClass::callWho(); // Output: ChildClass

Explanation:

  • static::who() in callWho() resolves to the who() method in the calling class.
  • When ChildClass calls callWho(), it dynamically binds to ChildClass::who().

Comparison Table

FeatureEarly Binding (self)Late Static Binding (static)
Resolution TimeCompile timeRuntime
Reference ContextThe class where the method is definedThe class that is calling the method
PolymorphismDoes not respect polymorphismRespects polymorphism
Keyword Usedselfstatic
Behavior with InheritanceAlways binds to the parent class method (if called in the parent)Dynamically binds to the calling class method

Key Points to Consider

  • Use early binding (self) when the behavior should always be tied to the parent class and should not change with inheritance.
  • Use late static binding (static) when you want polymorphic behavior, allowing the method or property resolution to adapt to the calling class at runtime.

Practical Example Comparing Both

class ParentClass { public static function who() { return "ParentClass"; } public static function earlyCall() { return self::who(); // Early binding } public static function lateCall() { return static::who(); // Late static binding } } class ChildClass extends ParentClass { public static function who() { return "ChildClass"; } } echo ParentClass::earlyCall(); // Output: ParentClass echo ChildClass::earlyCall(); // Output: ParentClass (early binding) echo ParentClass::lateCall(); // Output: ParentClass echo ChildClass::lateCall(); // Output: ChildClass (late static binding)

This highlights how self locks behavior to the defining class, while static allows dynamic resolution based on the calling class.

Thank you.

Sunday, 17 November 2024

Change config php 8.1

1. Update php.ini

upload_max_filesize = 128M post_max_size = 128M max_execution_time = 300

2. Restart php 8.1

sudo systemctl restart php8.1-fpm

3. View Config

<?php phpinfo(); ?>

Thank you

Wednesday, 16 October 2024

Optimize using memory in php with Generators

In PHP, a generator provides a memory-efficient way to handle large datasets or streams of data by producing values one at a time, rather than loading everything into memory at once. This can significantly reduce memory usage when working with large datasets, as it avoids the need to store the entire dataset in memory.

Key Concepts:

  1. Standard Iteration (Without Generators):

    • When using a regular function that returns a large dataset, PHP loads the entire dataset into memory at once, which can consume a lot of memory, especially for large collections of data.
  2. Generators:

    • A generator allows you to iterate over a sequence of values without having to create and store the entire sequence in memory. It works by "yielding" values one at a time.
    • Instead of returning a full array, the yield keyword returns one value at a time during each iteration.

Example:

Here's how a generator works in PHP compared to regular iteration:

Without a Generator (High Memory Usage):

function largeDataset() { $data = []; foreach (/* large data source */ as $item) { $data[] = $item; } return $data; } foreach (largeDataset() as $data) { process($data); }
  • This function returns the entire dataset as an array.
  • The entire array must be stored in memory, which can be problematic for large datasets, causing high memory usage.

With a Generator (Memory Efficient):

function largeDataset() { foreach (/* large data source */ as $data) { yield $data; // Yield returns one value at a time } } foreach (largeDataset() as $data) { process($data); }
  • The yield keyword in this function produces one value at a time.
  • Instead of returning a complete array, the generator produces values lazily, meaning it only generates the next value when needed.
  • This avoids loading the entire dataset into memory at once.

How Generators Work:

  • When you call a generator function, it doesn't execute immediately. Instead, it returns an object of type Generator.
  • Each time you iterate over the generator (using foreach or similar), PHP resumes execution of the generator from where it left off, until it hits the next yield.
  • The generator pauses and saves its state after each yield, allowing you to continue later without reloading all the data.

Benefits of Using Generators:

  1. Memory Efficiency: Since only one value is stored in memory at a time, this greatly reduces the memory footprint.
  2. Improved Performance: In cases where you don't need to process the entire dataset at once, generators improve performance by handling one piece of data at a time.
  3. Streaming Large Data: Generators are useful for working with large files or database queries where you can process data in chunks, instead of loading everything into memory.

Example of a Real Use Case:

Imagine you are processing a large CSV file:

function readLargeCsv($filename) { $handle = fopen($filename, 'r'); while (($row = fgetcsv($handle)) !== false) { yield $row; // Yield each row from the CSV } fclose($handle); } foreach (readLargeCsv('hugefile.csv') as $row) { process($row); // Process each row one by one without loading the entire file into memory }
  • In this case, only one row of the CSV file is in memory at any given time, even if the file contains millions of rows. This prevents memory exhaustion and allows you to process very large files efficiently.

Conclusion:

Using generators in PHP is an excellent technique to optimize memory usage and improve performance, particularly when dealing with large datasets. The key advantage is that you only work with one piece of data at a time, which allows you to process large data sources without overwhelming system resources.

Thank you

Thursday, 3 October 2024

Isset(), empty(), and checking a variable for true behave in PHP

Key Differences:

Variable Stateisset()empty()$var == true
Unset/undefinedfalse (Notice)true (No Notice)Notice/Error
nullfalsetruefalse
"" (empty string)truetruefalse
falsetruetruefalse
0truetruefalse
1truefalsetrue
"0" (string "0")truetruefalse
truetruefalsetrue
Non-empty string "abc"true            falsetrue        
[]true            truefalse

 

 Thank you

Monday, 23 September 2024

Autoloading in PHP

* Auto loading with Composer and PSR-4

I use Composer with PSR-4 for autoloading in PHP. This approach automatically loads classes and files by mapping class namespaces to directory structures. It provides several benefits:

  • No need to manually load classes.
  • Keeps the codebase cleaner and more organized.
  • Loads only the necessary classes, reducing memory usage.
  • Improves overall performance.
Thank you

Sunday, 19 May 2024

Deployer for deploy PHP project

1. File deploy.php

<?php
namespace Deployer;
require 'recipe/symfony.php';

// Config #############################################
$projects = [
    'projectA' => [
        'deploy_path' => '/var/www/projectA.com',
        'deploy_branch' => 'develop',
        'env_file' => 'config/projectA.com/.env'
    ],
    'projectB' => [
        'deploy_path' => '/var/www/projectB.com',
        'deploy_branch' => 'staging',
        'env_file' => 'config/projectB.com/.env'
    ]
];
// set repository
set('repository', 'git@github.com:<your_git_repository>.git');
// Number of releases to keep
set('keep_releases', 3);

// Hosts
foreach ($projects as $project => $config) {
    localhost($project)
        ->set('deploy_path', $config['deploy_path'])
        ->set('branch', $config['deploy_branch'])
        ->set('env_file', $config['env_file']);;
}

// Tasks
set('git_tty', true);
set('composer_action', 'update');
add('shared_files', ['.env']);
add('shared_dirs', ['vendor', 'node_modules']);
add('writable_dirs', ['var', 'html']);
set('allow_anonymous_stats', false);

// Tasks
desc('Deploy project');
task('deploy', [
    'deploy:prepare',
    'deploy:copy_env',
    'deploy:vendors',
    'deploy:node_modules',
    'deploy:eccube',
    'deploy:set_permissions',
    'deploy:publish',
]);

// Custom task to copy environment-specific files
task('deploy:copy_env', function () {
    $envFile = get('env_file');
    run("cp $envFile {{release_path}}/.env");
});

// Task to install composer dependencies
task('deploy:vendors', function () {
    run('cd {{release_path}} && composer install');
});

// Task to install composer dependencies
task('deploy:node_modules', function () {
    run('cd {{release_path}} && npm install');
    run('cd {{release_path}} && npm run build');
});

// Custom task to run additional commands
task('deploy:eccube', function () {
    run('cd {{release_path}} && bin/console eccube:generate:proxies');
    run('cd {{release_path}} && bin/console eccube:schema:update --force --dump-sql');
    run('cd {{release_path}} && bin/console cache:clear');
});

// Custom task to set permissions
task('deploy:set_permissions', function () {
    run('chmod -R 777 {{release_path}}/html');
    run('chmod -R 777 {{release_path}}/var');
});

// If deploy fails automatically unlock.
- after('deploy:failed', 'deploy:unlock');

2.  /etc/apache2/sites-available/projectA.com

<VirtualHost *:80>
ServerAdmin admin@projectA.com

ServerName projectA.com

ServerAlias www.projectA.com

DocumentRoot /var/www/projectA.com/current

<Directory /var/www/projectA.com/current>
Options FollowSymLinks
AllowOverride All
Require all granted
</Directory>

ErrorLog ${APACHE_LOG_DIR}/error.log

CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

3. Run deploy

$ vendor/bin/dep deploy projectA

* Solve problem permission 

(i) sudo chown folder release for www-data:www-data

- you need remove enter password when call sudo 

/ sudo visudo => edit:
{username } ALL=(ALL:ALL) NOPASSWD: ALL
/ note: need connect server again to use sudo 

(ii) Change user run apache 2

run: sudo nano /etc/apache2/envvars

# export APACHE_RUN_USER=www-data
# export APACHE_RUN_GROUP=www-data

export APACHE_RUN_USER=phong
export APACHE_RUN_GROUP=phong

- phong is user you ssh remote to your server 

(iii) Change user run Nginx

- add group for user: $ sudo usermod -aG www-data phong

- run: sudo nano /etc/nginx/nginx.conf

user phong phong;

* Change user run PHP-fpm
sudo nano /etc/php/8.1/fpm/pool.d/www.conf 
user = phong 
group = phong
...
listen.owner = phong
listen.group = phong


 - phong is user you ssh remote to your server

 

Thank you

Publish npm package

  Để publish   pav-kit  lên NPM, bạn hãy làm theo các bước dưới đây. Tôi đã tạo thêm file  index.js  để đảm bảo gói tin hợp lệ. Bước 1: Tạo ...