package runner import ( "bytes" "context" "io/ioutil" "os" "os/exec" "path/filepath" "time" "github.com/google/uuid" ) type PHPRunner struct { TempDir string } func (r *PHPRunner) Run(ctx context.Context, code string) (*ExecutionResult, error) { workDir := filepath.Join(r.TempDir, uuid.New().String()) if err := os.MkdirAll(workDir, 0755); err != nil { return nil, err } defer os.RemoveAll(workDir) filePath := filepath.Join(workDir, "script.php") if err := ioutil.WriteFile(filePath, []byte(code), 0644); err != nil { return nil, err } cmd := exec.CommandContext(ctx, "php", "script.php") cmd.Dir = workDir var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr startTime := time.Now() err := cmd.Run() duration := time.Since(startTime).Milliseconds() result := &ExecutionResult{ Output: stdout.String(), Error: stderr.String(), Duration: duration, } if err != nil { if exitErr, ok := err.(*exec.ExitError); ok { result.ExitCode = exitErr.ExitCode() } else { result.ExitCode = -1 } if ctx.Err() == context.DeadlineExceeded { result.Error += "\nExecution timed out" } } return result, nil }