Wednesday, May 21, 2025

In PHP, "false" can be true

All values loaded from an environment (.env) file using vlucas/phpdotenv are treated as strings, regardless of how they appear in the file. Even if your .env file contains IS_IN_SANDBOX_MODE = false, $_ENV['IS_IN_SANDBOX_MODE'] will be "false". The following condition would evaluate to true, even though the variable in the .env file is set to false, because "false" is a non-empty string and thus truthy in PHP:

if (IS_IN_SANDBOX_MODE) --> if ("false") --> true

This is a common gotcha when working with environment variables in PHP. To address this, you can use:

define('IS_IN_SANDBOX_MODE', filter_var($_ENV['IS_IN_SANDBOX_MODE'],
    FILTER_VALIDATE_BOOLEAN));

Note that FILTER_VALIDATE_BOOLEAN will return null for values like "True", "FALSE", "TRUE", etc. if (null) evaluates to false. It will return true for "true" (lowercase), "1", "on", or "yes". It will return false for "false" (lowercase), "0", "off", "no", or an empty string "".

Alternatively, my personal preference (because it makes the string conversion explicit):

define('IS_IN_SANDBOX_MODE', $_ENV['IS_IN_SANDBOX_MODE'] === 'true');

Or, when using it in a condition:

if (IS_IN_SANDBOX_MODE === 'true')

Wednesday, May 7, 2025

React Native Parameter Passing

When building mobile apps with React Native, we often face a decision about how to pass data between components - especially to screen components. Let's examine two common approaches and when to use each:

1. Direct Props Passing:

interface AddressInfoProps {
    cartItems: CartItem[];
    discountPrice: number;
}
const AddressInfo: React.FC<AddressInfoProps> = ({ cartItems, discountPrice }) => {
    // Component implementation
};

2. Navigation Route Parameters:

import { useRoute, RouteProp } from '@react-navigation/native';
type AddressInfoRouteProp = RouteProp<{
    AddressInfo: {
        cartItems: CartItem[];
        discountPrice: number;
    };
}, 'AddressInfo'>;
const AddressInfo: React.FC = () => {
    const route = useRoute<AddressInfoRouteProp>();
    const { cartItems, discountPrice } = route.params;
    // Component implementation
};

Option 1 is simpler, but it lacks built-in mechanisms to persist state when navigating back and forth between screens. You must always explicitly pass the parameters, meaning the developer is responsible for state persistence. Use it when the component is part of a larger component hierarchy where the parent already has the necessary data to pass down.

Use route parameters (Option 2) when the component represents a screen in your navigation flow—i.e., when backward and forward navigation is expected. With Option 2, the React Native navigation system handles state automatically. If the user navigates to another page and then presses the back button, the screen will re-render with its previous state.

Other options:

Context API: Best for data needed by many components at different nesting levels, but avoid for frequently changing data as it can cause unnecessary re-renders

State Management Libraries (Redux, MobX, Zustand, Jotai): Best for complex applications with lots of shared state and interactions between different parts of the app

URL Parameters: Best for web applications where maintaining bookmarkable state is important

Local Storage: Best for persisting data between app sessions like login status

Monday, May 5, 2025

Storing auth tokens on mobile

React Native AsyncStorage is a simple key-value storage system that saves data as plain text. This means that anyone with access to the device or its backups can potentially read your auth tokens, API keys, or other sensitive data if you use AsyncStorage.

Storing sensitive data unencrypted can also violate Google Play and AppStore guidelines which might result in your app being rejected. Reviewers might run basic security tests that could expose unencrypted token storage.

SecureStore is Expo's abstraction layer that leverages the native security infrastructure of both iOS and Android platforms. SecureStore automatically encrypts all data before storage and provides a unified API that works identically on both iOS and Android. While SecureStore has slightly more overhead due to encryption/decryption operations, the performance impact is negligible for typical use cases like token storage. The security benefits far outweigh any minor performance considerations.