$max ) { /* translators: %s: internal name of the submitted field. */ throw new InvalidArgumentException( esc_html( sprintf( __( 'Field is too long: %s', 'buildmerce-agent-orders' ), $key ) ) ); } return $value; } /** Strict dot-decimal input; reject exponent notation, overflow, negatives and silent rounding. */ public static function money( $value, $decimals ) { if ( ! is_int( $decimals ) || $decimals < 0 || $decimals > 6 ) { throw new InvalidArgumentException( esc_html__( 'This plugin supports currencies with zero to six decimal places.', 'buildmerce-agent-orders' ) ); } if ( ! is_scalar( $value ) ) { throw new InvalidArgumentException( esc_html__( 'Enter a valid positive price.', 'buildmerce-agent-orders' ) ); } $value = trim( (string) $value ); $pattern = 0 === $decimals ? '/^\d{1,8}$/' : '/^\d{1,8}(?:\.\d{1,' . $decimals . '})?$/'; if ( ! preg_match( $pattern, $value ) ) { /* translators: %d: number of decimal places supported by the store currency. */ throw new InvalidArgumentException( esc_html( sprintf( __( 'Enter a positive price with no more than %d decimal places. Use a dot as the decimal separator.', 'buildmerce-agent-orders' ), $decimals ) ) ); } $parts = explode( '.', $value ); $minor = (int) $parts[0] * ( 10 ** $decimals ) + (int) str_pad( isset( $parts[1] ) ? $parts[1] : '', $decimals, '0' ); if ( $minor < 1 || $minor > 999999999 ) { throw new InvalidArgumentException( esc_html__( 'Price is outside the supported range.', 'buildmerce-agent-orders' ) ); } return $minor; } public static function decimal( $minor, $decimals ) { if ( 0 === $decimals ) { return (string) $minor; } $factor = 10 ** $decimals; return intdiv( $minor, $factor ) . '.' . str_pad( (string) ( $minor % $factor ), $decimals, '0', STR_PAD_LEFT ); } public static function request( $data, $decimals ) { $result = array(); foreach ( array( 'product_name', 'sku', 'client_email', 'first_name', 'last_name', 'company', 'po' ) as $key ) { $result[ $key ] = self::text( $data, $key ); } foreach ( array( 'product_name', 'sku', 'client_email' ) as $key ) { if ( '' === $result[ $key ] ) { throw new InvalidArgumentException( esc_html__( 'Product name, SKU, price and client email are required.', 'buildmerce-agent-orders' ) ); } } if ( ! is_email( $result['client_email'] ) ) { throw new InvalidArgumentException( esc_html__( 'Enter a valid client email address.', 'buildmerce-agent-orders' ) ); } $qty = self::text( $data, 'quantity', 5 ); $qty = '' === $qty ? '1' : $qty; if ( ! preg_match( '/^[1-9]\d{0,3}$/', $qty ) ) { throw new InvalidArgumentException( esc_html__( 'Quantity must be a whole number from 1 to 9999.', 'buildmerce-agent-orders' ) ); } $result['quantity'] = (int) $qty; $result['unit_minor'] = self::money( isset( $data['price'] ) ? $data['price'] : '', $decimals ); $total = $result['unit_minor'] * $result['quantity']; if ( $total > 999999999 ) { throw new InvalidArgumentException( esc_html__( 'The order total exceeds the supported range.', 'buildmerce-agent-orders' ) ); } $result['total'] = self::decimal( $total, $decimals ); $result['price'] = self::decimal( $result['unit_minor'], $decimals ); foreach ( array( 'customer_note', 'internal_note' ) as $key ) { if ( isset( $data[ $key ] ) && ! is_scalar( $data[ $key ] ) ) { throw new InvalidArgumentException( esc_html__( 'Invalid note.', 'buildmerce-agent-orders' ) ); } $result[ $key ] = sanitize_textarea_field( isset( $data[ $key ] ) ? $data[ $key ] : '' ); if ( strlen( $result[ $key ] ) > 2000 ) { throw new InvalidArgumentException( esc_html__( 'Notes must be less than 2000 bytes.', 'buildmerce-agent-orders' ) ); } } return $result; } }