Monday, 11 December 2023

ngrok tunnel

./ngrok http -host-header=rewrite local.reeyysy.cc:80

Use config file to run multi tunnels

  • find config file location.
    ./ngrok authtoken 23siywfFYojsSVe8ojvO0yTEgf4_7dsx9xsdsfffdwww
  • set up config file
  • start tunnels
    ./ngrok start --all

Sample config file

bind_tls means https only to save endpoints


authtoken: 23siywfFYojsSVe8ojvO0yTEgf4_7dcnsnsdfskflfl
tunnels:
  webpack:
    proto: http
    addr: 8090
    host_header: rewrite
    domain: webpack.myseieie.ninja
    bind_tls: true
  cartSite:
    proto: http
    addr: 80
    domain: localhost
    host_header: rewrite
    bind_tls: true

Wednesday, 6 December 2023

React Context

React Context Docs

How to work

  • Create a context
  • Create a context provider component. Add values in the provide
  • Wrap components with the provider component
  • For these wrapped components, can use useContext to access values

Create Context Sample Code

export const placeContext = createContext();

//create a function component PlaceContextProvider
const PlaceContextProvider = ({ children }) => {
  const [places, dispatch] = useReducer(placeReducer, []);
  return (
    <placeContext.Provider value={{ places, dispatch }}>
      {children}
    </placeContext.Provider>
  );
};

export default PlaceContextProvider;

Main parts to create a context

  1. call createContext()// const placeContext = createContext();
  2. Create a context provider component. Set values property when create this component.
  3. export the above context provider

Use context provider

import PlaceContextProvider from "./contexts/place";

function App() {
  return (
    <div className="App">
      <PlaceContextProvider>
        <Nav />
        <PlaceList />

        <PlaceForm />
      </PlaceContextProvider>
    </div>
  );
}

export default App;

Main parts to use context provider

  1. import context provider
  2. wrap components which will use context in the context provider

Use context in a component

import { placeContext } from "../contexts/place";

export default function Nav() {
  const { places } = useContext(placeContext);
  return <h1>You have visited {places.length} places.</h1>;
}

Main parts to use context in a component

  1. import context (not context provider)
  2. pass the context as paramter of useConext function
  3. destruct the result which is values we pass to context provider
  4. use these values in the component

Tuesday, 28 November 2023

Stripe Webhook

Stripe provides with webhooks for event such as checkout.session.completed.

Set up webhook

  • log into Stripe
  • Click developer tab
  • Click webhook tab
  • following instruction to create a webhook

See Webhook successful or failed event

  • log into Stripe and go to webhook tab (see above)
  • click a webhook in the list of webhooks
  • click one event log in the list of event
  • Should see the details of request and response of the event

Test webhook in local server

  • ./ngrok http -host-header=rewrite local.reeyysy.cc:80
  • set up webhook using url generated by ngrok
  • try to fire an event
  • if failed, log into Stripe and find the failed event. Click resend to send event again.

Friday, 27 October 2023

Google Pay

Introduction

Google Pay for the web is built on the Payment Request API, an open web standard candidate that relies on the customer's browser as a secure intermediary for payments.

What is Payment Request API

It is one part of Web Payments standard.

Web Payments is an emerging web standard being developed by the W3C to simplify online payments. Web Payments consist of the following web standards:

  • Payment Request API
  • Payment Handler API
  • Payment Method Identifiers
  • Payment Method Manifest
//sample code for Payment Request
const request = new PaymentRequest(paymentMethods, paymentDetails);
request.canMakePayment().then(result => {
  if (result) {
    // This browser supports the specified payment method.
  } else {
    // This browser does NOT support the specified payment method.
  }
}).catch(e => {
  // An exception
});

Standalone page to show Google Pay

Google Pay Tutorial

<html>
<head>
    <script async src="https://pay.google.com/gp/p/js/pay.js" onload="onGooglePayLoaded()"></script>
    <script>
        const tokenizationSpec = {
            type: 'PAYMENT_GATEWAY',
            parameters: {
                gateway: 'example',
                gatewayMerchantId: 'gatewayMerchantId'
            }
        };

        const cardPaymentMethod = {
            type: 'CARD',
            tokenizationSpecification: tokenizationSpec,
            parameters: {
                allowedCardNetworks: ['VISA', 'AMEX'],
                allowedAuthMethods:
                    ['PAN_ONLY', 'CRYPTOGRAM_3DS'],
                billingAddressRequired: true,
                billingAddressParameters: {
                    format: 'FULL',
                    phoneNumberRequired: true
                }
            }
        }

        function onGooglePayLoaded() {
            const googlePayClient = new google.payments.api.PaymentsClient({ environment: "TEST" });

            const clientConfiguration = {
                apiVersion: 2,
                apiVersionMinor: 0,
                allowedPaymentMethods: [cardPaymentMethod]
            };

            googlePayClient.isReadyToPay(clientConfiguration)
                .then(function (response) {
                    console.log(response)
                    if (response.result) {
                        //create button
                        let button = googlePayClient.createButton({
                            buttonColor: 'default',
                            buttonType: 'long',
                            onClick: handleSubmit
                        })

                        document.getElementById('gp').appendChild(button);
                    }
                }).catch(function (err) {
                });

            function handleSubmit() {
                const paymentDataRequest = Object.assign({}, clientConfiguration);
                paymentDataRequest.transactionInfo = {
                    totalPriceStatus: 'FINAL',
                    totalPrice: '123.45',
                    currencyCode: 'USD'
                }

                paymentDataRequest.merchantInfo = {
                    merchantId: '0123456789',
                    merchantName: 'Example Merchant'
                }

                googlePayClient.loadPaymentData(paymentDataRequest)
                    .then(function (paymentData) {
                        console.log("payment data:", paymentData)
                    })
            }
        }

        
    </script>
</head>

<body>
    <p>Try Google Pay</p>
    <p id="gp"></p>
</body>

</html>

Local development

  • if it is localhost, Google allows it to be http
  • let a gmail to joined into sandbox test group and do not need to provide card when click "Google Pay button"

Join sandbox test group

Thursday, 26 October 2023

JSON Web Tokens

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

For JWT token, it consists of three parts:

  • header about alg and type
  • payload
  • signature

PHP codes to generate a JWT


    function createJWT($payload, $secret)
    {
        //this is alg used
        $header = ["typ" => "JWT", "alg" => "HS256"];

        $encodedHead = base64url_encode(json_encode($header));
        $encodedPayLoad = base64url_encode(json_encode($payload));

        //build the first two parts
        $encodedHeaderAndPayload = $encodedHead . '.' . $encodedPayLoad;

        $signature = base64url_encode(hash_hmac('sha256', $encodedHeaderAndPayload, $secret, true));

        //build token
        return $encodedHeaderAndPayload. '.' . $signature;
    }

    function base64url_encode($data)
    {
        return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
    }

Wednesday, 11 October 2023

Multiple UpSell

React Hook Form

React Hook Form Tutorial

//sample
const [books, dispatch] = useReducer(bookReducer, [])

useReducer Hook

The idea behind it is the same as reduc. Here is useReducer doc

React Context

Here is react context toturial

  • Provider needs to wrap a children when return a provider. Here children has a special meaning of children components
  • in App.js, components will be wrapped by context provider
  • In the component itself, it can access context in three ways
    • contextType
    • consumer
    • const {isLight, light} = useContext(ThemeContext)

In Context file, we need to export both context and context provider

  • export const AuthContext = createContext()
  • export default AuthConextProvider (This is a component with AuthContext.Provider)

Monday, 11 September 2023

Environment variables in docker

To view variables

  1. Log into container
  2. printenv
  3. printenv PATH

Other options

//in linux
env

//use echo
echo $PATH

To set variables

//to set
export <NAME>='<value>'

//for example to set value for MYPET
export MYPET='cutedog'

//to confirm
printenv MYPET

Set env variable in aws cloudformation

To inject sensitive data into your containers as environment variables, use the secrets container definition parameter.

  • Create parameter in AWS parameter store
  • Add it in cloudformation template
//code snippet. ExecutionRoleArn is needed because of Secrets and the role needs read permission to access parameter store
TaskDefinition:
    Type: "AWS::ECS::TaskDefinition"
    Properties:
      Family: !Sub "${AWS::StackName}"
      NetworkMode: bridge
      TaskRoleArn: !FindInMap [BuildEnvironment, !Ref 'EnvironmentType', "role"]
      ExecutionRoleArn: !FindInMap [BuildEnvironment, !Ref "EnvironmentType", "executionRole"]
      ContainerDefinitions:
          Secrets:
            - Name: GOOGLE_DRIVE_CREDENTIALS
              ValueFrom: !Sub "arn:aws:ssm:${AWS::Region}:12345678:parameter/GOOGLE_ACCOUNT-${EnvironmentType}"

Use shell script to check environment variables

#check to see if env variable HOME is set
if [[ -n "${HOME}" ]]; then
    echo "$HOME"
else
    echo "Homeless"
fi

Set environment varaibles in Dockerfile

FROM php:8.3.11RC2-zts-alpine3.20

ENV GCT_PROJECT='fluid-fiber-84848484'
ENV GCT_KEY='AIzaSyCejejsllswororowwppw'

Sunday, 10 September 2023

Google reCAPTCHA

Step one: sign up recaptcha in Google.

It is free. Get GOOGLE_RECHAPTCHA_SECRET and GOOGLE_RECHAPTCHA_SITE_KEY

Need to add domain with this recaptcha. Do not need to add sub domain. Can add multiple domains

Step two: client side

<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<div class="g-recaptcha" data-callback="recaptchaCallback" data-sitekey="{$siteKey}"></div>

//after check, may want to hide error. Put codeback code here
var recaptchaCallback = function() {

}

Step three: server side validation

User response can be found in $_POST['g-recaptcha-response']

public static function verifyRecaptcha($userResponse)
{
    $url = "https://www.google.com/recaptcha/api/siteverify";
    $curl = curl_init($url);

    $post = ['secret' => getenv('GOOGLE_RECHAPTCHA_SECRET'), 'response' => $userResponse];
    $post = http_build_query($post);

    curl_setopt($curl, CURLOPT_POSTFIELDS, $post);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "POST");

    $response = curl_exec($curl);
    curl_close($curl);

    //see what we get
    $result = json_decode($response, true);

    return $result['success'] ?? false;
}

React component for Google reCAPTCHA v2

npm install --save react-google-recaptcha

Friday, 1 September 2023

Stripe Javascript Cart

create a session

        \Stripe\Stripe::setApiKey($this->getSecret());
        $data = [
            'payment_method_types' => ['card'],
            'line_items' => [[
                'price_data' => [
                    'currency' => $currencyCode,
                    'product_data' => [
                        'name' => $productName,
                    ],
                    'unit_amount' => $amountWithoutDecimal,
                ],
                'quantity' => $quantity,
            ]],
            'metadata' => [
                "order_id" => $orderID,
                'order_type' => $orderType,
                'user_id'=> $userId,
               
            ],
            'client_reference_id' => "{$orderType}_{$orderID}",
            'mode' => 'payment',
            'success_url' => $this->getSuccessUrl(),
            'cancel_url' => $this->getCancelUrl(),
        ];

        try {
            $session = \Stripe\Checkout\Session::create($data);
            return $session;
        } catch (Exception $e) {
            echo $e->getMessage();
        }

Initiate Cart By JavaScript


<script  type="text/javascript" src="https://js.stripe.com/v3/"></script>
const stripeSession = await fetch("/stripe/create-checkout-session.php", {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                },
                //info needed to create session
                body: JSON.stringify({
                    price: myPrice,
                    type: "product",
                    .....
                    
                }),
            })

            const data = await stripeSession.json()

            var stripe = Stripe('{$stripePublicKey}');
            stripe.redirectToCheckout({
                sessionId: data.sessionId,
            })

Process After Payment

When set up successful url, we can use the placeholder: session_id={CHECKOUT_SESSION_ID}

$successUrl = "https://example.com?session_id={CHECKOUT_SESSION_ID}";

when we create session, we can remember strip checkout session id in server side. Do compare in the successful url page and we know it is paid. Then we can do what we want for a successful transaction.

Tuesday, 18 July 2023

Create SSL/TSL Certificate in AWS ACM

cname name and cname value

cname allows to point a hostname to any other hostname. hostname1 maps to hostname2. Here hostname1 is called cname name and hostname2 is called cname value. cname name can not be root domain name. something.mydom.com works, but mydom.com can not be used to be cname name.

Can use dig command to find cname /cname value pair.

dig checkout.mytest.com

Request a certification in AWS ACM

  1. request a public certification. Also choose DNS validation
    • If record is in AWS route 53, AWS will do validation automatically and issued the certificate
    • If record is not in AWS route 53, grab the cname name and cname value provided by the certificate. Create a cname record in your domain registra, and AWS will verify it and issue the certificate

Add certificate to ELB

The default Limit for Certificates per Application Load Balancers is 25

  • Select the load balancer.
  • On the Listeners and rules tab, choose the text in the Protocol:Port (443) column to open the detail page for the listener.
  • On the Certificates tab, choose Add certificate.
  • Within the ACM and IAM certificates table, select the certificates to add and choose Include as pending below
  • Choose Add pending certificates.

Delete a certificate

  1. Got to ACM to find that certificate. Check if it is in use. If it is in use, write down which elbs are using it.
  2. If in use, go to elb. click cetificates, and check that certificate. Then click remove.
  3. After it is removed from all associated elbs, go back to ACM. Choose the certificate, and click delete

Monday, 17 July 2023

API Access-Control-Allow header


$response = $response->withHeader('Access-Control-Allow-Origin', "*");
$response = $response->withHeader('Access-Control-Allow-Credentials', 'true');
return $response->withHeader('Access-Control-Allow-Headers', 'X-Requested-With,
Content-Type, Accept, Origin, Authorization, X-Authorization-JWT, X-CSRF-Token')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');

Friday, 7 July 2023

MySQL Query

rank

# see leetcode 2173 https://leetcode.com/problems/longest-winning-streak/description/
select
    player_id,
    result,
    RANK () OVER (
        PARTITION BY player_id,
        result
        ORDER BY
            match_day
    ) as my_rank
from
    Matches
order by
    match_day

generate sequence


# 1 to 100
WITH RECURSIVE seq AS (
    SELECT 1 AS value UNION ALL SELECT value + 1 FROM seq WHERE value < 100
    )

create help tables


with platforms as (
select 'Android' as platform
union
select 'IOS' as platform
union
select 'Web' as platform
),

 activities as (
  select 'Reading' as experiment_name
  union
  select 'Sports' as experiment_name
  union
  select 'Programming' as experiment_name
)

More Queries

#day function converts timestamp to day. 2023-10-11 23:33:33 to 11

select day(created), partner_fid, count(*) from cpa_conversion where created>="2024-9-1" group by day(created), partner_fid;

Tuesday, 13 June 2023

where is my docker-compose

After upgrade docker desktop, docker-compose command can not be found.

But look at docker information the below, docker compose should be there.

which docker
/usr/local/bin/docker

cd /usr/local/bin/docker

//see a symoblic link
docker-compose -> /Applications/Docker.app/Contents/Resources/bin/docker-compose/docker-compose

//go to /Applications/Docker.app/Contents/Resources/bin/docker-compose and not find docker-compose
//ha ha directory structure changed in this new version of docker desktop
//to fix, in /usr/local/bin
rm docker-compose
ln -s /Applications/Docker.app/Contents/Resources/bin/docker-compose docker-compose

Tuesday, 23 May 2023

AWS Certificate Manager

DNS validation

ACM provides you with one or more CNAME records that must be added to this database. These records contain a unique key-value pair that serves as proof that you control the domain.

If use AWS Route 53, you can create a record of CNAME type for that domain. The CNAME name and CNAME value provided by ACM should be used.

Thursday, 27 April 2023

Modify Request Headers in Chrome

  • Install ModHeader extension in Chrome
  • Use that extension to set a header
  • Open developer tool, network tab
  • Visit a page
  • View request headers in developer tool
  • Make sure header sent indeed

Friday, 21 April 2023

docker compose

extra_hosts

Add hostname mappings. Function the same as the docker client --add-host parameter.

//example
extra_hosts:
  - "somehost:162.242.195.82"
  - "otherhost:50.31.209.229"

An entry with the ip address and hostname is created in /etc/hosts inside containers for this service

host.docker.internal

For docker for mac or window, it is docker host ip. However, for docker for Linux, need to add this in compose file

#For docker for Mac or Window, should not add this. Otherwise,
#host.docker.internal may not be host ip.  It is for Linux only
extra_hosts:
    - host.docker.internal:host-gateway

Sunday, 9 April 2023

Google Tag Management System

What is tag

Tag is a JS code snippet inserted into a web page to track user event. Meta pixel and Goggle ad are some example of tags

What problem we have if we use multiple tags in a web page

  • Will need to add a code snippet for every tag. For example, if we use five track tools from ten different company, we need to add 10 extra code snippets in different pages
  • If we want to change some thing such as account id, we need to go to every page to modify them

Google Tag Management System

Tag management system likes an container. You set up and update tags in the tag management system, and you only need one extra code snippent in a web page no matter how many tags you want to use. Google Tag Management System is one of these systems.

Use Google Tag Management System, and you can

  • Set up tags
  • Set up event rules

gtag.js

gtag.js is the JavaScript framework that is used to add Google tags directly to web pages. It can not add third party tags.

Here what we need is a tag id

// Google tag (gtag.js)
<script async src="https://www.googletagmanager.com/gtag/js?id=TAG_ID"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments)};
  gtag('js', new Date());

  gtag('config', 'TAG_ID');
</script>

The Google tag lets you send data from your website to linked Google product destinations. By now only Google Ads accounts and web data streams in GA4 properties can be destinations.

You can use a single Google tag across your entire website and connect the tag ID to multiple destinations.

Shopify

Enable custom app development from the Shopify admin

Before you can create a custom app for your store, you need to enable custom app development. You need to be the store owner or a staff member with the Enable app development permission to enable custom app development.

  1. From your Shopify admin, click Settings
  2. Click Apps and sales channels.
  3. Click Develop apps.
  4. Click Allow custom app development.
  5. Read the warning and information provided, and then click Allow custom app development.

Create an app

  • create a app called my-test
  • click Config Admin API scopes
  • choose services app needs such as customer, draft order, order and fullfillement services
  • click save configuration
  • install app and copy admin api token: shpat_559dummydummy77e77437574

Friday, 31 March 2023

Meta Tracking

Mata Pixel

Using Mata Pixel, we can send tracking data to Facebook. There are two ways to send tracking data.

  • Javascript
  • Conversion API

Javascript method

You need pixel id and event name. The below is sample code to send a PageView event

<script>
  !function(f,b,e,v,n,t,s)
  {if(f.fbq)return;n=f.fbq=function(){n.callMethod?
  n.callMethod.apply(n,arguments):n.queue.push(arguments)};
  if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
  n.queue=[];t=b.createElement(e);t.async=!0;
  t.src=v;s=b.getElementsByTagName(e)[0];
  s.parentNode.insertBefore(t,s)}(window, document,'script',
  'https://connect.facebook.net/en_US/fbevents.js');
  fbq('init', '{your-pixel-id-goes-here}');
  fbq('track', 'PageView');
</script>

There are two options to send event using Javascript

  • Emebed the above code snippet in the webpage
  • Run that code snippet directly. For example, for React page, we can run this Javascript code snippet directly using react hook useDidMountEffect

Test web browser events using the test events tool

  • Log into Facebook business account
  • Go to Events Manager
  • Click the Data sources icon on the middle side of the page
  • Click Test events
  • Find the browser events section
  • If do not see the browser events section, click clear event
  • Enter your website URL and click Open website. This opens your website in a separate window or tab
  • Do what you normally do to this website. Event will be recorded
  • Go back to Test Event section to check events recorded

Deduplication

If we send the same event using both conversion API and embedded javascript, Meta can use event id to deduplication. Meta will treat event with the same event id as the same event.

//use JS to send out event id
fbq('track', 'Purchase', {value: 12, currency: 'USD'}, {eventID: 'EVENT_ID'});

fbq('track', 'Lead', {}, {eventID: 'EVENT_ID'});

Specifications for Meta Pixel standard events

Developer Guide for Mata Pixel

Mata Conversion API

Coversion API Docs

React Tech Stack

Built in React Hook

Use Effect

Wednesday, 8 March 2023

Selenium

Install Selenium in Ubuntu

  1. pip install selenium
  2. download chrome webdriver Driver needs to match Chrome version installed in your machine
  3. unzip download files and copy chromedriver to /usr/bin folder
//hello_world.py
from selenium import webdriver

driver = webdriver.Chrome()
driver.maximize_window()

driver.get("https://developer-leoshen.blogspot.com/2023/03/selenium.html")

driver.find_element_by_link_text("download chrome webdriver").click()

driver.find_element_by_id("age3").click()

firstName = driver.find_element_by_id("first_name").send_keys("leo")
python hello_world.py

PHP Selenium

//installation
1. down stand alone selenium server

2. install php library
compose require php-webdriver/webdriver ^1.13.1

3. install chrome driver
//test.php
<?php
require_once(__DIR__ . '/vendor/autoload.php');

$host = 'http://localhost:4444/wd/hub';

$driver = Facebook\WebDriver\Remote\RemoteWebDriver::create($host, Facebook\WebDriver\Remote\DesiredCapabilities::chrome());

$driver->get("https://ca.yahoo.com");

$driver->manage()->window()->maximize();

$driver->quit();
//run standalone server
java -jar selenium-server-standalone-3.141.59.jar

//run test script
php test.php

The following is used for test script

Please select your age:






First Name :

Upgrade Chrome in my linux machine

sudo apt update
sudo apt upgrade

Thursday, 2 March 2023

AWS CLI Commands and profiles

multiple profiles in one machine

//who is calling
aws sts get-caller-identity

//list profiles
aws configure list-profiles

//add new profile for myone. set format: json default output format
//if does not add profile flag, the profile name is default
aws configure --profile myone

//use profile
aws sts get-caller-identity --profile myone

Some commands

# list lambda function
aws lambda list-functions

# overwrite default region
aws lambda list-functions --region us-west-1

Wednesday, 1 March 2023

postman

add variable in postman

  1. select environment such as local, sandbox
  2. select the environment quick look icon
  3. edit
  4. save

To use variable

{{api-key}}

See network info of a response

network icon is beside status:200 ok. can see remote ip etc

Wednesday, 15 February 2023

AWS Troubleshooting

CloudFormation stack stuck in an IN_PROGRESS state

AWS Docs For Troubleshooting

Here is an example

1. one stack is stuck at UPDATE_IN_PROGRESS
2. click resource tab and I can see AWS::ECS::Service is stuck in UPDATE_IN_PROGRESS
3. Go to ECS and find that service and click Logs tab
4. show get something from logs

ec2-user does not have permission to access mysql log file

After log into a EC2 machine, I try to access /vol/mysql/data/my_logs.txt. However, I get a permission deny.

# see all users in machine
vi /etc/passwd

# switch to root
sudo su - root

# now can see log
vi /vol/mysql/data/my_logs.txt

Wednesday, 8 February 2023

Access Container On AWS Fargate

Here is the documentation for Access Container On Fargate

#!/bin/bash

# if see error, most likely task id is changed because of new build
aws ecs execute-command \
--region us-west-1 \
--cluster my-ecs-microservice \
--task 709909fdf605c4d7f9c3c206af862abc \
--container sandbox-contauner-foo-1 \
--command "/bin/bash"  --interactive

Find Target Group of A ECS Service

  • Click that service
  • Click network tab

Friday, 27 January 2023

Jenkins

Available Environment Variables

//See a list of environment variables
https://jenkins.mycomany.dev/env-vars.html/

//access environment variable in Jenksfile
build = "Build:${BUILD_NUMBER}"

See work place

cd /home/jenkins/workspace 

Check which docker image used by stack

In template file, image is mapped to BuildVersion.

  • go to Cloudformation
  • find the stack
  • click parameters
  • check BuildVersion

withCredentials explained

When the withCredentials block is executed, the specified credentials are made available only within that block by injecting enviornment variables. Once the block execution is complete, the environment variables are no longer available, ensuring the secrets are not exposed outside the block

stages {
        stage('Example') {
            steps {
                // Wrap steps with the credentials
                withCredentials([usernamePassword(credentialsId: 'my-credentials-id', 
                                                  usernameVariable: 'USER', 
                                                  passwordVariable: 'PASS')]) {
                    // Use the credentials. It shows we can access env variables USER and PASS
                    // because these two env variables have been injected by withCredentials
                    // in real life, you will not echo these credentials, but use it in your codes
                    sh 'echo "Username: $USER"'
                    sh 'echo "Password: $PASS"'
                }
            }
        }
    }

To manage credentials in Jenkins, go to Manage Jenkins; go to Manage Credentials

Run bash in Jenkins

sh "rm -rf composer/composer.json composer/composer.lock composer/vendor"
sh "composer.phar require aws/aws-sdk-php ^3.69 --ignore-platform-reqs --working-dir=composer"

Tuesday, 24 January 2023

Magic function __invoke

In PHP, __invoke() method is called when a script tries to call an object as a function

//example 1
<?php
class CallableClass
{
    public function __invoke($x)
    {
        var_dump($x);
    }
}
$obj = new CallableClass;

//treat object as function. Here var dump 5
$obj(5);

//will get true
var_dump(is_callable($obj));

//example 2
<?php
class CallableClass
{
    public function __invoke($x)
    {
        return $x + 100;
    }
}
$obj = new CallableClass;

$ans = $obj(5);

//Here var dump 105
var_dump($ans);